0

I am working with Selenium and MSTest as framework and I would like to extend the TestClass, TestMethod and TestCleanup. Right now the tests are derived from a TestBase class that is defined as follows:

[TestClass]
public class TestBase : IDisposable
{
    bool disposed = false;
    SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);


    public TestContext TestContext { get; set; }

    protected HelperSelenium SeleniumHelper { get; set; }

    [TestInitialize]
    public void TestInitBase()
    {
        SeleniumHelper = new HelperSelenium(TestContext);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposed)
            return;

        if (disposing)
        {
            handle.Dispose();
            SeleniumHelper.GetWebDriver().Quit();
            // Free any other managed objects here.
            //
        }

        disposed = true;
    }
}

The [TestClass] instantiates TestContext and [TestInitialize] instantiates the HelperSelenium with TestContext as a paremeter (this is necessary to tell Selenium which class it should use depending on a TestContext property.

I've tried with this code without success:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class SeleniumTestClass : TestClassAttribute
{
    //Prueba para finalizacion de recursos
    bool disposed = false;
    /// <summary>
    /// Bandera para saber si se ha llamado a dispose e instanciacion de un Selfhandle
    /// </summary>
    SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);

    public TestContext TestContext { get; set; }

    public HelperSelenium SeleniumHelper { get; set; }

    #region Configuración Test

    [TestInitialize]
    public void TestInitBase()
    {
        SeleniumHelper = new HelperSelenium(TestContext);
    }

    public void Dispose()
    {
        //SeleniumHelper.GetWebDriver().Quit();
        //SeleniumHelper.GetWebDriver().Dispose();
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposed)
            return;

        if (disposing)
        {
            handle.Dispose();
            SeleniumHelper.GetWebDriver().Quit();
            // Free any other managed objects here.
            //
        }

        disposed = true;
    }

I would like to extend [TestClass] to [SeleniumTestClass] so if I use [SeleniumTestClass] in a derived class all of this would be done automatically. I've trying to do this because we are using EventFiringWebDriver which will throw an exception even inside a Wait.Until loop. Selenium can throw a exception in 2 ways:

  1. An action has been performed that throws an exception, but the exception is caught by Wait.Until
  2. An action has been performed that throws an exception, and the exception is outside a Wait.Until

So if TestMethod fails, I would be able to take a screenshot while catching the exception. I think TestCleanup cannot be inherited so I am not sure if I would be able to catch the exception in the TestCleanup

I know I could wrap up the TestMethod and the TestCleanup each one in a try-catch but that would be cumbersome to do in each test we have and the test we would be creating in the future.

Any help is appreciated.

elgato
  • 506
  • 1
  • 5
  • 20
  • Why not create an extension method on the IWebDriver interface that takes the screenshot? As long as you can get a pointer to the web driver you have a one liner that creates and saves the screenshot. This centralizes the logic for taking the screenshot without requiring you to bend the test framework in ways it wasn't meant to be used. – Greg Burghardt Sep 18 '19 at 22:43
  • Hi Greg, we do use extension methods however for the screenshot to be added to the test result files, you must pass TestContext, that would mean passing TestContext to all the PageObjects to finally pass it to the extension method, that's why I want to do it at the TestMethod level. Regards – elgato Sep 19 '19 at 13:59
  • The page objects should not need a TestContext object. If page objects need the TestContext then I would say that is an architectural flaw that needs to be corrected. – Greg Burghardt Sep 19 '19 at 15:03

1 Answers1

1

Try having the abstract class calling a new OnTest method:

[TestClass]
public abstract class TestBase 
{
    bool disposed = false;
    SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);


    public TestContext TestContext { get; set; }

    protected HelperSelenium SeleniumHelper { get; set; }

    [TestInitialize]
    public void TestInitBase()
    {
        SeleniumHelper = new HelperSelenium(TestContext);
    }

    public abstract void OnTest();

    [TestMethod()]
    public void SeleniumTest()
    {
        try
        {
            OnTest();
        }
        catch(Exception ex){
        }
    }
}