Separation of Concerns (SoC) is a basic programming principle that promotes maintainability and reusability. When creating Web Performance Tests (hereafter “Web Tests”), we are not exempt from following this principle. In this post we will introduce a feature of Web Tests that help us implement SoC in our tests (If you are not familiar with Web Performance Tests you may get started here).
The “Add call to Web Test” option of Web Tests is analogous to calling a function, allowing us to separate the concerns of our tests into separate “sub tests”.
To use it, you may right click into any part or your Web Test to insert a call to another Web Test:
Let us discuss a couple of examples of when this feature can be useful:
Log on is the canonical example of functionality that will constantly repeat in your test cases. You do not want to repeat this process in all of your Web Tests. If this is the case, any change in this process will break all of the Web Tests that involves logging in.
The alternative is to factor out the requests related to the process of logging in into its own Web Test. All tests that require logging in can simply call the “Log In” Web Test (SoC applied, the Web Test has one and only one purpose: to log in users). Then, if you need to update the login process, you can do it in one place.
Suppose that we’re developing tests against a local test environment, let’s call it: http://apptested. A few weeks later we need to run these tests against the staging environment. However, in this new environment, the application is located at http://stagingapp. Let’s also suppose that we wish to run these Web Tests against another deployment of this application, in this case named http://testenvironmentapp.
If the number of cases is relatively small, updating our performance tests is a relatively straight forward task. But as the number of cases or the number of times we need to “port” the tests to different environments increases, these tasks becomes tedious, error prone and time consuming.
How can we solve this problem? There are many possible approaches, one of them is using a Web Test whose only purpose is to initialize the context parameters. This approach is simple and elegant:
• The “ContextParameterInitializer” Web Test:
• A Web Test using the context parameters initialization technique, and its result:
• Another web performance test reusing the context parameters initialization technique, and its result:
When invoking external Web Tests, we need to keep in mind the following considerations:
Invoked Web Tests have an additional Boolean property called “Inherit Web Test Settings.” If this property is true then the child test (invoked test) will have access to the following artifacts from its parent (the invoker):
• Web Test properties • Validation rules • Web Test plug-ins
Regardless of this property, the Web Test context will always be passed by reference to the children and it will not be affected by this property. Hence, any changes that you make to the context on the child tests (or any new value that you add) will be available to the parent even after you have left the child test (and therefore these changes will also be available to any other Web Test called thereafter).
For illustrative purposes, here is a sample of the code that implements the invocation of external web tests. Line 18 is where the “Inherit Web Test Settings” comes into play. In line 36 the context of the parent tests is passed to the child as a reference. Notice that the context is always shared:
1: private WebTest IncludeWebTest(WebTest childWebTest,
2: bool ensureDataBindingInitialized, bool inheritWebTestSettings)
4: if (childWebTest == null)
5: throw new ArgumentNullException("childWebTest");
7: if (ensureDataBindingInitialized)
10: //If true, inherit the Web Test properties from the parent
11: if (inheritWebTestSettings)
12: childWebTest.InheritFromWebTest = this;
14: //Code to initialize necessary children properties based on the parent Web Test values
17: //If true, inherit all the webtest plugins from the parent
18: if (inheritWebTestSettings)
21: if (this.PreWebTest != null)
23: foreach (EventHandler<PreWebTestEventArgs> eventHandler in
25: childWebTest.PreWebTest += eventHandler;
27: //Perform the same code for the rest of the webtest plug-in events.
31: //Initialize the child Web Test context
32: //Pass the parent context as a reference
33: //All changes made on the children get propagated to the parent.
34: //Inherit Web Settings DO NOT affect the context inheritance
36: childWebTest.Context = this.Context;
37: childWebTest.ParentTestName = WebTest.GetSimpleName(this.Name);
38: return childWebTest;
In summary, “Add a call to Web Test” is a very useful feature of Web Tests. If used correctly, it will result in tests that are easier to understand, maintain, and update.