Reputation: 1875
I have a test class where the constructor is called before each test execution. The data initialized by the constructor is currently not shared among the following tests. I want this initialized data to be set up once and shared across all tests. Here's my code:
[Category("Basics")]
[Collection("DBCollection")]
[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");
...
}
Can you help me set it up so that the fixture is initialized once and its data is available to all test methods in this class?
Thanks in advance.
Upvotes: 49
Views: 96697
Reputation: 1399
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");
}
}
Upvotes: 58