Using a config file to override targets in a Visual Studio test project
I wanted one of my coded UI tests to work in different environments, and to do that I wanted to override one of the URLs. I wanted to set that up in a config file rather than a data source. So, I created my own configuration data class for a custom section in App.Config (MSDN Article here):
Configuration Data Class
- public class TestSiteConfigurationData : ConfigurationSection
- {
- private static ConfigurationPropertyCollection _Properties;
- private static bool _ReadOnly;
- private static readonly ConfigurationProperty _WebServerName = new ConfigurationProperty("WebServerName", typeof(string), "localhost", ConfigurationPropertyOptions.IsRequired);
- private static readonly ConfigurationProperty _WebServerPort = new ConfigurationProperty("WebServerPort", typeof(int), 80);
- private static readonly ConfigurationProperty _WebApplicationRootName = new ConfigurationProperty("WebApplicationRootName", typeof(string), "");
- public TestSiteConfigurationData()
- {
- //init properties
- _Properties = new ConfigurationPropertyCollection();
- _Properties.Add(_WebServerName);
- _Properties.Add(_WebServerPort);
- _Properties.Add(_WebApplicationRootName);
- }
- // Properties
- protected override ConfigurationPropertyCollection Properties
- {
- get
- {
- return _Properties;
- }
- }
- private new bool IsReadOnly
- {
- get
- {
- return _ReadOnly;
- }
- }
- // use this to disable property setting
- private void ThrowIfReadOnly(string propertyName)
- {
- if (IsReadOnly) throw new ConfigurationErrorsException("the property " + propertyName + " is read only.");
- }
- // this enables the ThrowIfReadOnly method
- protected override object GetRuntimeObject()
- {
- // to enable property setting just assign true to the following flag:
- _ReadOnly = true;
- return base.GetRuntimeObject();
- }
- public string WebServerName
- {
- get { return (string)this["WebServerName"]; }
- set
- {
- ThrowIfReadOnly("WebServerName");
- this["WebServerName"] = value;
- }
- }
- [IntegerValidator(MinValue=1, MaxValue=64000, ExcludeRange=false)]
- public int WebServerPort
- {
- get { return (int) this["WebServerPort"]; }
- set
- {
- ThrowIfReadOnly("WebServerPort");
- this["WebServerPort"] = value;
- }
- }
- public string WebApplicationRootName
- {
- get { return (string)this["WebApplicationRootName"]; }
- set
- {
- ThrowIfReadOnly("WebApplicationRootName");
- this["WebApplicationRootName"] = value;
- }
- }
- }
You’ll need to add a reference to the System.Configuration assembly for that to work. Adding annotations to validate the properties would also be a good idea.
Then I added the custom elements to my app.config file (which I added to my test project):
App.Config
- <?xml version="1.0"?>
- <configuration>
- <configSections>
- <section name="TestSiteConfigurationData"
- type="Ordermanagement.web.uitest.TestSiteConfigurationData, Ordermanagement.web.uitest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
- allowExeDefinition="MachineToApplication" restartOnExternalChanges="true"/>
- </configSections>
- <!--<TestSiteConfigurationData WebServerName="ordermanagement.hol.net" WebServerPort="80" WebApplicationRootName="" />-->
- <TestSiteConfigurationData WebServerName="ordermgtweb.hol.net" WebServerPort="80" WebApplicationRootName="OrderManagementWeb" />
- </configuration>
The “type” attribute is “[Configuration Class], [assembly holding your extension without the dll/exe suffix], [version], [culture], [key]”.
Next, I created a helper class to format the URL for me:
Helper Class
- public class TestSiteConfigurationHelper
- {
- TestSiteConfigurationData config;
- public TestSiteConfigurationData Config
- {
- get { return config; }
- set { config = value; }
- }
- public string RootUrl
- {
- get
- {
- UriBuilder urlBuilder = new UriBuilder();
- urlBuilder.Host = config.WebServerName;
- urlBuilder.Port = config.WebServerPort;
- urlBuilder.Path = config.WebApplicationRootName;
- return urlBuilder.Uri.ToString();
- }
- }
- public TestSiteConfigurationHelper()
- {
- config = (TestSiteConfigurationData)System.Configuration.ConfigurationManager.GetSection("TestSiteConfigurationData");
- }
- }
And I called the helper class to replace the recorded URL with the configured one (see lines 1 and 7 below):
Updated Coded UI block
- TestSiteConfigurationHelper configHelper = new TestSiteConfigurationHelper();
- // To generate code for this test, select "Generate Code for Coded UI Test" from the shortcut menu and select one of the menu items.
- // For more information on generated code, see go.microsoft.com/fwlink/?LinkId=179463
- this.UIMap.LaunchBrowser();
- //override url
- this.UIMap.NavigatetohttpordermgtholnetParams.UIBlankPageWindowsInteWindowUrl = configHelper.RootUrl; //default "ordermanagement.hol.net/";
- this.UIMap.Navigatetohttpordermgtholnet();
- this.UIMap.ClickonLoginlink();
- this.UIMap.LoginasusernameusernamepasswordpasswordParams.UIUsernameEditText = TestContext.DataRow["username"].ToString();
- this.UIMap.LoginasusernameusernamepasswordpasswordParams.UIPasswordEditPassword = Playback.EncryptText(TestContext.DataRow["password"].ToString());
- this.UIMap.Loginasusernameusernamepasswordpassword();
There are more properties you’d want to overload, but I haven’t done that here. Vishal Joshi has a blog post that describes how to transform the app.config file for different build configurations, and that’s something else I’d like to do.
Some housekeeping is probably a good idea, but this is just a simple example.