【问题标题】:xunit constructor runs before each testxunit 构造函数在每次测试之前运行
【发布时间】:2020-03-17 22:25:57
【问题描述】:

在测试类中,构造函数在每次测试之前启动,构造函数提供的初始化数据不能被以下测试访问。

我希望所有测试都可以访问初始化数据。 (只能创建一次)

[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");
        ...
    }

提前致谢。

【问题讨论】:

  • 在创建派生类的实例时,您必须调用基类的构造函数。 XUnit 在这方面并没有什么不同。但是,您可能根本不使用构造函数,而是使用设置方法?
  • 这是每个测试用例从一个新的初始化对象开始的正常方式。您不知道要运行的案例的年表,因此您不应该创建需要连续运行的测试并操作被测类。如果某些案例有其他初始化 - 在 testcasemethod 中重新创建/指定它并继续。
  • XUnit 默认并行执行测试。在测试之间共享状态/值可能会导致奇怪的行为、无缘无故的失败等。

标签: c# unit-testing xunit


【解决方案1】:

您可以使用 Xunit 类灯具。使用类夹具时,xUnit.net 将确保在任何测试运行之前创建夹具实例,并且一旦所有测试完成,它将通过调用 Dispose(如果存在)来清理夹具对象。例如:

//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
}

对于每个测试,它都会创建一个新的 MyDatabaseTests 实例,并将 DatabaseFixture 的共享实例传递给构造函数。

Xunit 文档here

希望对你有帮助。

28/10 编辑 对于多个夹具,您可以创建一个封装其他两个夹具的类,如下所示,并创建启动夹具以在 db 夹具之前运行:

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
        }
    }
}

和测试类:

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");
    }
}

【讨论】:

  • 我用fixture做别的东西,你可以在代码中看到它是StartUpFixture,是否可以有多个fixture?并按顺序运行它们?首先 startUpFixture 然后是 DbFixture
  • 如果你的fixture对象不是在类之间共享的,这很有效。对于我的问题,理想的情况是在您的 Selenium、Web UI 测试中。当我们把驱动对象放到了intern实现这个IClassFixture的基类中,这个驱动对象怎么在其他继承基类的类中被访问?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-03
  • 1970-01-01
  • 1970-01-01
  • 2015-05-30
  • 1970-01-01
相关资源
最近更新 更多