xUnit测试因共享静态数据而失败

时间:2018-12-01 13:13:28

标签: c# unit-testing xunit

我有几个使用某些静态类的单元测试,例如:

public static class Utility
{
    private static Data data;

    public static void Init(Data data)
    {
        this.data = data;
    }

    public static void Process()
    {
        // Some actions that changes this.data (not reference, just inner Values)
    }
}

public class Data
{
    public List<string> Values { get; set; }

    public void Add(string value)
    {
        Values.Add(value);
    }
}

每个单元测试都会初始化Data实例并将其传递给Utility:

[Fact]
public void UnitTest1()
{
    var data = new Data();
    data.Add("val1");
    Utility.Init(data);

    Utility.Process();

    // check changed data instance
}

[Fact]
public void UnitTest2()
{
    var data = new Data();
    data.Add("another_val1");
    data.Add("another_val2");
    Utility.Init(data);

    Utility.Process();

    // check changed data instance
}

如果我分别运行每个测试,则没有问题-没有失败的测试。 但是,如果我按顺序运行测试,则单元测试之一将失败,因为尽管调用了Utility.Init,但Utility.data包含来自先前测试的实例(短时间)。 如果我通过命令行运行测试(测试执行得非常快),则大部分测试很可能由于相同的原因而失败。我该如何解决这个问题?

1 个答案:

答案 0 :(得分:3)

由于静态实用程序的性质,所有测试都在访问共享的静态资源,这可能已经产生负面影响。我建议使实用程序类成为实例类

public class Utility
{
    private Data data;

    public Utility(Data data) {
        this.data = data;
    }

    public void Process() {
        // Some actions that changes this.data (not reference, just inner Values)
    }
}

哪个示例测试看起来像

[Fact]
public void UnitTest1() {
    //Arrrange
    var data = new Data();
    data.Add("val1");
    var subject = new Utility(data);

    //Act
    subject.Process();

    //Assert
    // check changed data instance
}

我怀疑初始化问题是XY problem,并且该实用程序还被用作生产中的静态依赖项,这是代码的味道。

在这种情况下,抽象静态实用程序类

public interface IUtility {
    void Process(Data data);
}

并重构实现

public class Utility : IUtility {

    public void Process(Data data) {
        // Some actions that changes this.data (not reference, just inner Values)
    }
}

这将导致测试看起来像

[Fact]
public void UnitTest1() {
    //Arrrange
    var data = new Data();
    data.Add("val1");
    var subject = new Utility();

    //Act
    subject.Process(data);

    //Assert
    // check changed data instance
}

[Fact]
public void UnitTest2() {
    var data = new Data();
    data.Add("another_val1");
    data.Add("another_val2");
    var subject = new Utility();

    //Act
    subject.Process(data);

    //Assert
    // check changed data instance
}

IUtility将根据需要注入到相关类中,这将使生成的代码更可靠。