【问题标题】:xUnit tests are failed with shared static dataxUnit 测试因共享静态数据而失败
【发布时间】:2018-12-01 22:25:30
【问题描述】:

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

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.data 包含来自先前测试的实例(短时间内),尽管有 Utility.Init 调用。 如果我通过命令行运行测试(测试执行得非常快),那么大部分测试很可能由于同样的原因而失败。我该如何解决这个问题?

【问题讨论】:

  • 由于静态实用程序的性质,所有测试都在访问共享静态资源,这可能会产生负面影响,就像已经体验过的那样。我建议将实用程序类设为实例类

标签: c# unit-testing xunit


【解决方案1】:

由于静态实用程序的性质,所有测试都在访问共享静态资源,这可能会产生负面影响,正如已经体验过的那样。我建议将实用程序类设为实例类

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 将根据需要注入到依赖类中,这将使生成的代码更加可靠。

【讨论】:

  • 我尝试完全不使用静态并得到相同的效果。问题不在于静态。可能在复制对象引用时:subject.Process(data); 和副作用
  • @user190794 如果使用新实例,则先前的测试无法访问另一个实例的数据
  • @user190794 Process 使用一些共享资源吗?
  • 来自Data 的属性Values(参见我的示例)是静态的,这是我的错误。同意@Nkosi 的建议
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-23
  • 1970-01-01
  • 2021-11-20
  • 1970-01-01
  • 2019-11-21
  • 2012-05-27
相关资源
最近更新 更多