47

In a test class, the constructor starts before each test and the initialized data provided by the constructor isn't reachable by the following tests.

I'd like the initialized data to be accessible for all tests. (be created only once)

[Category("Basics")]
[Collection("DD")]
[ExcludeFromCodeCoverage]
public class SecurityTests : TestUnitBase
{
    StartUpFixture fixture;
    public AuthenticationTests(StartUpFixture fixture)
       : base()
    {
        this.fixture = fixture;
    }

    [Fact(DisplayName = "Successful response Test1")]
    public void SuccessfulResponseTest1()
    {
        var users = base.Db.Users.FirstOrDefault(x => x.Name == "abc");
        ...
    }

    [Fact(DisplayName = "Successful response Test2")]
    public void SuccessfulResponseTest2()
    {
        var users = base.Db.Users.FirstOrDefault(x => x.Name == "xyz");
        ...
    }

Thanks in advance.

Mojtaba Khooryani
  • 1,763
  • 1
  • 17
  • 36
  • 1
    When creating an instance of a derived class you *have* to call a constructor of the base-class. XUnit isn´t different on this. However you may simply not use the constructor at all but the Setup-methods? – MakePeaceGreatAgain Oct 25 '17 at 07:53
  • 2
    it´s the normal way that each testcase starting with a new initialized object. you don´t know the cronology of the cases to run so you should not create tests which need to be run in a row and manipulate class under test. if some cases got other inits - recreate/specify this in the testcasemethod and go on. – LenglBoy Oct 25 '17 at 07:55
  • 1
    XUnit executes tests in parallel by default. Having shared state/values between tests can lead to strange behaviour, failed tests with no reasons etc. – Fabio Oct 27 '17 at 11:47

1 Answers1

55

You can use Xunit Class fixtures. When using a class fixture, xUnit.net will ensure that the fixture instance will be created before any of the tests have run, and once all the tests have finished, it will clean up the fixture object by calling Dispose, if present. For example:

//similar to base class
public class DatabaseFixture : IDisposable
{
    public SqlConnection Db { get; private set; }
    public DatabaseFixture()
    {
        Db = new SqlConnection("MyConnectionString");

        // initialize data in the test database
    }

    public void Dispose()
    {
        // clean up test data from the database
    }
}

//Class where you want to use shared class instance
public class MyDatabaseTests : IClassFixture<DatabaseFixture>
{
    DatabaseFixture dbFixture;

    public MyDatabaseTests(DatabaseFixture fixture)
    {
        this.dbFixture = fixture;
    }

    // write tests, using dbFixture.Db to get access to the SQL Server
}

For each test, it will create a new instance of MyDatabaseTests, and pass the shared instance of DatabaseFixture to the constructor.

Xunit Documentation here.

Hope it helps.

Edit 28/10 For multiple fixtures you can create a class which encapsulates the other two fixtures as below and create startup fixture to run before db fixture:

public class SecurityTestsFixture : IDisposable
{
    public DatabaseFixture Dbfixture { get; private set; }
    public StartupTestFixture Startupfixture { get; private set; }

    public SecurityTestsFixture()
    {
        Startupfixture = new StartupTestFixture();
        Dbfixture = new DatabaseFixture(Startupfixture);
    }

    public void Dispose()
    {
        // clean up code
        Dbfixture.Dispose();
    }

    public class StartupTestFixture
    {
        public string SqlConnString { get; private set; }
        public StartupTestFixture()
        {
            SqlConnString = ConfigurationManager.AppSettings["SqlConnectionString"];

            // other startup code
        }
    }

    public class DatabaseFixture : IDisposable
    {
        public SqlConnection Db { get; private set; }
        public DatabaseFixture(StartupTestFixture sFixture)
        {
            Db = new SqlConnection(sFixture.SqlConnString);

            // initialize data in the test database
        }

        public void Dispose()
        {
            // clean up test data from the database
        }
    }
}

and test class:

public class Xunittests : IClassFixture<SecurityTestsFixture>
{
    SecurityTestsFixture _securityFixture;
    public Xunittests(SecurityTestsFixture securityfixture)
    {
        _securityFixture = securityfixture;
    }

    [Fact(DisplayName = "Successful response Test1")]
    public void SuccessfulResponseTest1()
    {
        var db = _securityFixture.Dbfixture.Db;
        //var users = db.Users.FirstOrDefault(x => x.Name == "...");
        Assert.Equal("test", "test");
    }
}
Shah
  • 1,319
  • 1
  • 13
  • 18
  • 1
    I used fixture for something else, as you can see it's StartUpFixture in code, is it possible to have muliple fixture? and run them in order? first startUpFixture then DbFixture – Mojtaba Khooryani Oct 28 '17 at 07:17
  • This workes well if your fixture object is not to be shared between classes. For my problem ideal case would be in your Selenium, web UI testing. When we have placed the driver object in the base class which intern implements this IClassFixture, how can this driver object be accessed in other classes which inherits the base class? – Raghavendra Bankapur Jan 08 '19 at 10:45