Click here to Skip to main content
15,867,686 members
Articles / Programming Languages / C#

Create Hybrid Test Framework- Abstract Unit Test Framework

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
2 Oct 2016Ms-PL3 min read 5.7K   3  
The next step in building a Hybrid Test Automation Framework is to abstract the unit test framework layer. Learn how to switch it without changes in tests.

Introduction

The newest article from the Design & Architecture Series is going to be dedicated to another abstraction. My colleagues and I decided that NUnit will be our preferred unit testing framework for our projects. However, all of our existing automation tests depend on MSTest. So we decided to add a new layer of abstraction and create a solution where you can easily choose which unit test framework you want to use.

Abstract Unit Test Framework

We created a new separate project where all abstract unit test framework's items are placed called HybridTestFramework.Core.Asserts. The different concrete implementations reference the project and implement the interface it provides.

IAssert Interface

This is the interface that all concrete implementations need to implement. It doesn't include all methods that exist, but you can add them on demand. Include only the ones that you use in your tests.

C#
public interface IAssert
{
    void AreEqual(object expected, object actual);

    void AreEqual(object expected, object actual, string message);

    void AreEqual<T>(T expected, T actual) where T : class;

    void AreEqual<T>(T expected, T actual, string message) where T : class;

    void AreNotEqual(object expected, object actual);

    void AreNotEqual(object expected, object actual, string message);

    void AreNotEqual<T>(T expected, T actual) where T : class;

    void AreNotEqual<T>(T expected, T actual, string message) where T : class;

    void IsFalse(bool condition);

    void IsFalse(bool condition, string message);

    void IsTrue(bool condition);

    void IsTrue(bool condition, string message);
        
    void IsNull(object value);

    void IsNull(object value, string message);

    void IsNotNull(object value);

    void IsNotNull(object value, string message);

    void Fail(string message);

    void IsInstanceOfType(object value, Type expectedType);

    void IsInstanceOfType(object value, Type expectedType, string message);
}

Global Assert Wrapper

The second member of the HybridTestFramework.Core.Asserts project is the static Assert class. In general, it is a wrapper of the interface. It is going to use the last registration in the global Unity IoC Container for the IAssert interface. In your page objects' asserts, you use this class because it doesn't depend on any unit test framework. This way, your core tests' projects do not rely on any particular framework. There are going to use the concrete implementation you register in your container, and only your tests' projects will carry the particular references.

C#
public static class Assert
{
    private static readonly IAssert assert;

    static Assert()
    {
        assert = UnityContainerFactory.GetContainer().Resolve<IAssert>();
    }

    public static void AreEqual(object expected, object actual)
    {
        assert.AreEqual(expected, actual);
    }

    public static void AreEqual(object expected, object actual, string message)
    {
        assert.AreEqual(expected, actual, message);
    }

    public static void AreEqual<T>(T expected, T actual) where T : class
    {
        assert.AreEqual<T>(expected, actual);
    }

    public static void AreEqual<T>(T expected, T actual, string message) where T : class
    {
        assert.AreEqual<T>(expected, actual, message);
    }

    public static void AreNotEqual(object expected, object actual)
    {
        assert.AreNotEqual(expected, actual);
    }

    public static void AreNotEqual(object expected, object actual, string message)
    {
        assert.AreNotEqual(expected, actual, message);
    }

    public static void AreNotEqual<T>(T expected, T actual) where T : class
    {
        assert.AreNotEqual<T>(expected, actual);
    }

    public static void AreNotEqual<T>(T expected, T actual, string message) where T : class
    {
        assert.AreNotEqual<T>(expected, actual, message);
    }

    public static void IsFalse(bool condition)
    {
        assert.IsFalse(condition);
    }

    public static void IsFalse(bool condition, string message)
    {
        assert.IsFalse(condition, message);
    }

    public static void IsTrue(bool condition)
    {
        assert.IsTrue(condition);
    }

    public static void IsTrue(bool condition, string message)
    {
        assert.IsTrue(condition, message);
    }

    public static void IsNull(object value)
    {
        assert.IsNull(value);
    }

    public static void IsNull(object value, string message)
    {
        assert.IsNull(value, message);
    }

    public static void IsNotNull(object value)
    {
        assert.IsNotNull(value);
    }

    public static void IsNotNull(object value, string message)
    {
        assert.IsNotNull(value, message);
    }

    public static void Fail(string message)
    {
        assert.Fail(message);
    }

    public static void IsInstanceOfType(object value, Type expectedType)
    {
        assert.IsInstanceOfType(value, expectedType);
    }

    public static void IsInstanceOfType(object value, Type expectedType, string message)
    {
        assert.IsInstanceOfType(value, expectedType, message);
    }
}

Concrete Asserts Implementations

MSTest Implementation

For the concrete MSTest implementation of the IAssert interface, we create a separate project called HybridTestFramework.Core.MSTest.Asserts where the MSTestAssert class is situated. Of course, it should reference Microsoft.VisualStudio.QualityTools.UnitTestFramework assembly. The methods only wrap the actual MSTest's assert methods.

C#
public class MSTestAssert : IAssert
{
    public void AreEqual(object expected, object actual)
    {
        VSU.Assert.AreEqual(expected, actual);
    }

    public void AreEqual(object expected, object actual, string message)
    {
        VSU.Assert.AreEqual(expected, actual, message);
    }

    public void AreEqual<T>(T expected, T actual) where T : class
    {
        VSU.Assert.AreEqual<T>(expected, actual);
    }

    public void AreEqual<T>(T expected, T actual, string message) where T : class
    {
        VSU.Assert.AreEqual<T>(expected, actual, message);
    }

    public void AreNotEqual(object expected, object actual)
    {
        VSU.Assert.AreNotEqual(expected, actual);
    }

    public void AreNotEqual(object expected, object actual, string message)
    {
        VSU.Assert.AreNotEqual(expected, actual, message);
    }

    public void AreNotEqual<T>(T expected, T actual) where T : class
    {
        VSU.Assert.AreNotEqual<T>(expected, actual);
    }

    public void AreNotEqual<T>(T expected, T actual, string message) where T : class
    {
        VSU.Assert.AreNotEqual<T>(expected, actual, message);
    }

    public void Fail(string message)
    {
        VSU.Assert.Fail(message);
    }

    public void IsFalse(bool condition)
    {
        VSU.Assert.IsFalse(condition);
    }

    public void IsFalse(bool condition, string message)
    {
        VSU.Assert.IsFalse(condition, message);
    }

    public void IsInstanceOfType(object value, Type expectedType)
    {
        VSU.Assert.IsInstanceOfType(value, expectedType);
    }

    public void IsInstanceOfType(object value, Type expectedType, string message)
    {
        VSU.Assert.IsInstanceOfType(value, expectedType, message);
    }

    public void IsNotNull(object value)
    {
        VSU.Assert.IsNotNull(value);
    }

    public void IsNotNull(object value, string message)
    {
        VSU.Assert.IsNotNull(value, message);
    }

    public void IsNull(object value)
    {
        VSU.Assert.IsNull(value);
    }

    public void IsNull(object value, string message)
    {
        VSU.Assert.IsNull(value, message);
    }

    public void IsTrue(bool condition)
    {
        VSU.Assert.IsTrue(condition);
    }

    public void IsTrue(bool condition, string message)
    {
        VSU.Assert.IsTrue(condition, message);
    }
}

NUnit Implementation

For the concrete NUnit implementation of the IAssert interface, we create a separate project called HybridTestFramework.Core.NUnit.Asserts where the NunitAssert class is present. You should install the NUnit NuGet. The class's methods only call the NUnit's assert methods.

C#
public class NunitAssert : IAssert
{
    public void AreEqual(object expected, object actual)
    {
        NUF.Assert.That(actual, NUF.Is.EqualTo(expected));
    }
        
    public void AreEqual(object expected, object actual, string message)
    {
        NUF.Assert.That(actual, NUF.Is.EqualTo(expected), message);
    }

    public void AreEqual<T>(T expected, T actual) where T : class
    {
        NUF.Assert.That<T>(actual, NUF.Is.EqualTo(expected));
    }

    public void AreEqual<T>(T expected, T actual, string message) where T : class
    {
        NUF.Assert.That<T>(actual, NUF.Is.EqualTo(expected), message);
    }

    public void AreNotEqual(object expected, object actual)
    {
        NUF.Assert.That(actual, NUF.Is.Not.EqualTo(expected));
    }

    public void AreNotEqual(object expected, object actual, string message)
    {
        NUF.Assert.That(actual, NUF.Is.Not.EqualTo(expected), message);
    }

    public void AreNotEqual<T>(T expected, T actual) where T : class
    {
        NUF.Assert.That<T>(actual, NUF.Is.Not.EqualTo(expected));
    }

    public void AreNotEqual<T>(T expected, T actual, string message) where T : class
    {
        NUF.Assert.That<T>(actual, NUF.Is.Not.EqualTo(expected), message);
    }

    public void Fail(string message)
    {
        NUF.Assert.Fail(message);
    }

    public void IsFalse(bool condition)
    {
        NUF.Assert.That(condition, NUF.Is.False);
    }

    public void IsFalse(bool condition, string message)
    {
        NUF.Assert.That(condition, NUF.Is.False, message);
    }

    public void IsInstanceOfType(object value, Type expectedType)
    {
        NUF.Assert.That(value, NUF.Is.TypeOf(expectedType));
    }

    public void IsInstanceOfType(object value, Type expectedType, string message)
    {
        NUF.Assert.That(value, NUF.Is.TypeOf(expectedType), message);
    }

    public void IsNotNull(object value)
    {
        NUF.Assert.That(value, NUF.Is.Not.Null);
    }

    public void IsNotNull(object value, string message)
    {
        NUF.Assert.That(value, NUF.Is.Not.Null, message);
    }

    public void IsNull(object value)
    {
        NUF.Assert.That(value, NUF.Is.Null);
    }

    public void IsNull(object value, string message)
    {
        NUF.Assert.That(value, NUF.Is.Null, message);
    }

    public void IsTrue(bool condition)
    {
        NUF.Assert.That(condition, NUF.Is.True);
    }

    public void IsTrue(bool condition, string message)
    {
        NUF.Assert.That(condition, NUF.Is.True, message);
    }
}

Abstract Unit Test Framework in Tests

Page Asserter

Your page asserter's project is no more obligated to reference the Microsoft.VisualStudio.QualityTools.UnitTestFramework assembly. You only need to add a reference to the HybridTestFramework.Core.Asserts. After that, exchange the using statements as in the example.

C#
////using Microsoft.VisualStudio.TestTools.UnitTesting;
using HybridTestFramework.Core.Asserts;

namespace AbstractUnitTestFramework.Pages.BingMain
{
    public static class BingMainPageAsserter
    {
        public static void AssertResultsCountIsAsExpected(
            this BingMainPage page, 
            string expectedResultCount)
        {
            Assert.AreEqual(
                page.ResultsCountDiv.Content, 
                expectedResultCount,
                "The results count is not as expected.");
        }
    }
}

MSTest Example

The only special thing that you need to do is the last registration in the global Unity container - UnityContainerFactory.GetContainer().RegisterType<IAssert, MSTestAssert>(). This way, the asserts of your pages will start working with MSTest.

C#
[TestClass]
public class BingTestsMsTest
{
    private IDriver driver;

    [TestInitialize]
    public void SetupTest()
    {
        UnityContainerFactory.GetContainer().RegisterType
        <IDriver, TestingFrameworkDriver>();
        UnityContainerFactory.GetContainer().RegisterType
        <INavigationService, TestingFrameworkDriver>();
        UnityContainerFactory.GetContainer().RegisterType
        <IBrowser, TestingFrameworkDriver>();
        UnityContainerFactory.GetContainer().RegisterType
        <ICookieService, TestingFrameworkDriver>();
        UnityContainerFactory.GetContainer().RegisterType
        <IDialogService, TestingFrameworkDriver>();
        UnityContainerFactory.GetContainer().RegisterType
        <IElementFinder, TestingFrameworkDriver>();
        UnityContainerFactory.GetContainer().RegisterType
        <IJavaScriptInvoker, TestingFrameworkDriver>();

        UnityContainerFactory.GetContainer().RegisterType<IInputSubmit, InputSubmit>();
        UnityContainerFactory.GetContainer().RegisterType<ISearch, Search>();
        UnityContainerFactory.GetContainer().RegisterType<IDiv, Div>();
        UnityContainerFactory.GetContainer().RegisterType<BingMainPage>();

        UnityContainerFactory.GetContainer().RegisterInstance
        <IUnityContainer>(UnityContainerFactory.GetContainer());
        UnityContainerFactory.GetContainer().RegisterInstance
        <BrowserSettings>(BrowserSettings.DefaultChomeSettings);
        this.driver = UnityContainerFactory.GetContainer().Resolve<IDriver>();

        UnityContainerFactory.GetContainer().RegisterInstance<IDriver>(this.driver);
        UnityContainerFactory.GetContainer().RegisterInstance<IBrowser>(this.driver);
        UnityContainerFactory.GetContainer().RegisterInstance<ICookieService>(this.driver);
        UnityContainerFactory.GetContainer().RegisterInstance<IDialogService>(this.driver);
        UnityContainerFactory.GetContainer().RegisterInstance<IJavaScriptInvoker>(this.driver);
        UnityContainerFactory.GetContainer().RegisterInstance<INavigationService>(this.driver);
        UnityContainerFactory.GetContainer().RegisterInstance<IElementFinder>(this.driver);

        // Register the concrete Unit Testing Framework.
        UnityContainerFactory.GetContainer().RegisterType<IAssert, MSTestAssert>();
    }

    [TestMethod]
    public void SearchForAutomateThePlanet()
    {
        var bingMainPage = UnityContainerFactory.GetContainer().Resolve<BingMainPage>();
        bingMainPage.Navigate();
        bingMainPage.Search("Automate The Planet");
        bingMainPage.AssertResultsCountIsAsExpected("422,000 results");
    }
}

NUnit Example

The examples are completely identical with the only difference that the second one uses NUnit unit test framework. Instead of registering MSTestAssert class for the IAssert interface, we use the NunitAssert.

C#
[TestFixture]
public class BingTestsNUnit
{
    private IDriver driver;

    [SetUp]
    public void Init()
    {
        UnityContainerFactory.GetContainer().RegisterType
        <IDriver, TestingFrameworkDriver>();
        UnityContainerFactory.GetContainer().RegisterType
        <INavigationService, TestingFrameworkDriver>();
        UnityContainerFactory.GetContainer().RegisterType
        <IBrowser, TestingFrameworkDriver>();
        UnityContainerFactory.GetContainer().RegisterType
        <ICookieService, TestingFrameworkDriver>();
        UnityContainerFactory.GetContainer().RegisterType
        <IDialogService, TestingFrameworkDriver>();
        UnityContainerFactory.GetContainer().RegisterType
        <IElementFinder, TestingFrameworkDriver>();
        UnityContainerFactory.GetContainer().RegisterType
        <IJavaScriptInvoker, TestingFrameworkDriver>();

        UnityContainerFactory.GetContainer().RegisterType<IInputSubmit, InputSubmit>();
        UnityContainerFactory.GetContainer().RegisterType<ISearch, Search>();
        UnityContainerFactory.GetContainer().RegisterType<IDiv, Div>();
        UnityContainerFactory.GetContainer().RegisterType<BingMainPage>();

        UnityContainerFactory.GetContainer().RegisterInstance
        <IUnityContainer>(UnityContainerFactory.GetContainer());
        UnityContainerFactory.GetContainer().RegisterInstance
        <BrowserSettings>(BrowserSettings.DefaultChomeSettings);
        this.driver = UnityContainerFactory.GetContainer().Resolve<IDriver>();

        UnityContainerFactory.GetContainer().RegisterInstance<IDriver>(this.driver);
        UnityContainerFactory.GetContainer().RegisterInstance<IBrowser>(this.driver);
        UnityContainerFactory.GetContainer().RegisterInstance<ICookieService>(this.driver);
        UnityContainerFactory.GetContainer().RegisterInstance<IDialogService>(this.driver);
        UnityContainerFactory.GetContainer().RegisterInstance<IJavaScriptInvoker>(this.driver);
        UnityContainerFactory.GetContainer().RegisterInstance<INavigationService>(this.driver);
        UnityContainerFactory.GetContainer().RegisterInstance<IElementFinder>(this.driver);

        // Register the concrete Unit Testing Framework.
        UnityContainerFactory.GetContainer().RegisterType<IAssert, NunitAssert>();
    }

    [Test]
    public void SearchForAutomateThePlanet()
    {
        var bingMainPage = UnityContainerFactory.GetContainer().Resolve<BingMainPage>();
        bingMainPage.Navigate();
        bingMainPage.Search("Automate The Planet");
        bingMainPage.AssertResultsCountIsAsExpected("422,000 results");
    }
}

Design & Architecture

The post Create Hybrid Test Framework- Abstract Unit Test Framework appeared first on Automate The Planet.

All images are purchased from DepositPhotos.com and cannot be downloaded and used for free.
License Agreement

This article was originally posted at http://automatetheplanet.com/abstract-unit-test-framework

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
CEO Automate The Planet
Bulgaria Bulgaria
CTO and Co-founder of Automate The Planet Ltd, inventor of BELLATRIX Test Automation Framework, author of "Design Patterns for High-Quality Automated Tests: High-Quality Test Attributes and Best Practices" in C# and Java. Nowadays, he leads a team of passionate engineers helping companies succeed with their test automation. Additionally, he consults companies and leads automated testing trainings, writes books, and gives conference talks. You can find him on LinkedIn every day.

Comments and Discussions

 
-- There are no messages in this forum --