Running selenium against multiple browsers with MSTEST Running selenium against multiple browsers with MSTEST selenium selenium

Running selenium against multiple browsers with MSTEST


This is what I did. The benefit of this approach is that it will work for any test framework (mstest, nunit, etc) and the tests themselves don't need to be concerned with or know anything about browsers. You just need to make sure that the method name only occurs in the inheritance hierarchy once. I have used this approach for hundreds of tests and it works for me.

  1. Have all tests inherit from a base test class (e.g. BaseTest).
  2. BaseTest keeps all driver objects (IE, FireFox, Chrome) in an array (multiDriverList in my example below).
  3. Have the following methods in BaseTest:

    public void RunBrowserTest( [CallerMemberName] string methodName = null ){                  foreach( IDriverWrapper driverWrapper in multiDriverList ) //list of browser drivers - Firefox, Chrome, etc. You will need to implement this.    {        var testMethods = GetAllPrivateMethods( this.GetType() );        MethodInfo dynMethod = testMethods.Where(                tm => ( FormatReflectionName( tm.Name ) == methodName ) &&                  ( FormatReflectionName( tm.DeclaringType.Name ) == declaringType ) &&                  ( tm.GetParameters().Where( pm => pm.GetType() == typeof( IWebDriver ) ) != null ) ).Single();        //runs the private method that has the same name, but taking a single IWebDriver argument        dynMethod.Invoke( this, new object[] { driverWrapper.WebDriver } );     }} //helper method to get all private methods in hierarchy, used in above methodprivate MethodInfo[] GetAllPrivateMethods( Type t ){    var testMethods = t.GetMethods( BindingFlags.NonPublic | BindingFlags.Instance );    if( t.BaseType != null )    {        var baseTestMethods = GetAllPrivateMethods( t.BaseType );        testMethods = testMethods.Concat( baseTestMethods ).ToArray();    }    return testMethods;}//Remove formatting from Generic methodsstring FormatReflectionName( string nameIn ){                return Regex.Replace( nameIn, "(`.+)", match => "" );}
  4. Use as follows:

    [TestMethod]public void RunSomeKindOfTest(){    RunBrowserTest(); //calls method in step 3 above in the base class}private void RunSomeKindOfTest( IWebDriver driver ){    //The test. This will be called for each browser passing in the appropriate driver in each case    ...            }     


To do this, we wrote a wrapper around webdriver and we use a switch statement based on a property to select the browser type.

Here's a snippet. Using the DesiredCapabilities, you can tell grid which browsers to execute against.

switch (Controller.Instance.Browser)            {                case BrowserType.Explorer:                    var capabilities = DesiredCapabilities.InternetExplorer();                    capabilities.SetCapability("ignoreProtectedModeSettings", true);                    Driver = new ScreenShotRemoteWebDriver(new Uri(uri), capabilities, _commandTimeout);                    break;                case BrowserType.Chrome:                    Driver = new ScreenShotRemoteWebDriver(new Uri(uri), DesiredCapabilities.Chrome(), _commandTimeout);                    break;            }


This idea is better for an automated CI scenario rather than interactive UI, but you can use a runsettings file and declare a parameter in that:

<?xml version='1.0' encoding='utf-8'?><RunSettings>    <TestRunParameters>        <Parameter name="SELENIUM_BROWSER" value="Firefox" />    </TestRunParameters></RunSettings>

You'll need a TestContext on your Test class

public TestContext TestContext { get; set; }

Then in your MSTest when you initialise the Driver you can check which browser you want to run

switch (TestContext.Properties["SELENIUM_BROWSER"]?.ToString()){    case BrowserType.Chrome:        return new ChromeDriver();    case BrowserType.Edge:        return new EdgeDriver();    case BrowserType.Firefox:        return new FirefoxDriver();}

You would then run the suite of tests n times, once for each runsettings file