【问题标题】:Run each theory in different test class在不同的测试类中运行每个理论
【发布时间】:2022-01-26 14:13:00
【问题描述】:

假设我有一个带有理论方法的测试类,该方法使用两个输入“无关”和“无关2”运行。测试首先检查是否有静态类“IsInitialized”,如果有,则测试失败。

然后,测试通过调用“Initialize”来初始化静态类。

[Theory]
[InlineData("irrelevant")]
[InlineData("irrelevant2")]
public void Test(string param)
{
    if (MyStaticClass.IsInitialized()) { throw new Exception(); }
    MyStaticClass.Initialize();
}

public static class MyStaticClass
{
    private static bool Initialized = false;

    public static void Initialize()
    {
        Initialized = true;
    }

    public static bool IsInitialized()
    {
        return Initialized;
    }
}

我希望两个测试都能通过,因为静态类仅在调用“Initialize”后才被初始化。但是,结果是第一次测试通过,第二次失败,因为静态类保留在内存中。我希望静态类状态恢复到初始状态。我可以理解为什么会发生这种情况,因为使用了静态。但是,我试图弄清楚是否有一种方法可以配置测试以释放静态类的内存,就好像我会运行一个新的测试用例一样。

如果我有两个包含相同代码的“事实”,也会发生这种情况。当分别运行每个事实时,两个测试都会通过。运行测试类时,一个会通过(第一个),第二个会失败。

【问题讨论】:

  • 这就是为什么您的测试应该独立于副作用的原因。在测试方法中初始化 SUT 所需的一切,不要依赖测试类中的静态值。确保所有测试可以以任何顺序和/或并行运行,以确保您的测试结果稳定。如果你不能确保这一点,那么你就有一个必须修复的设计缺陷。
  • 如果我测试静态类本身会怎样?在这种情况下,副作用无关紧要,因为这是测试用例。我用一个新的例子更新了这个问题。

标签: c# unit-testing static xunit


【解决方案1】:

您所描述的是预期行为。如果在一次测试中将静态字段Initialized 的值设置为“true”,那么当您运行下一个测试时,它将为“true”。

有几种方法可以查看:

  • 如果您要测试的只是设置字段值确实有效,请不要测试。这与其说是代码的行为,不如说是语言的一个特性。我们是否需要编写测试来验证设置属性是否真的设置了它?可能不会。
  • 如果您必须对其进行测试,请不要编写如果语言正常工作就必须失败的测试。编写一个测试来验证该值是否为您设置的值。验证值 不是 的测试不是很有用。
  • 考虑不使用static 类和属性。使用静态类与实例类的原因特定于您正在编码的任何内容。我不知道你的原因。但我们在测试时遇到的挑战通常反映了我们在“真正”使用代码时会遇到的问题。
  • 您问是否可以从内存中“处理”它。你不能这样做,或者至少这样做的过程太复杂了,你不应该这样做。您可以向静态类添加一个“重置”值的方法。但这有点乱。如果我们必须向静态类添加方法只是为了测试它们,那么也许我们应该考虑不使用静态类。

【讨论】:

  • 这显然不是完整的代码。我正在测试的是 Initialize 方法初始化类属性,并且它只能初始化一次(在实际代码中,在第二次调用时初始化会抛出)。在这种情况下必须使用静态类,我不能使用实例类。这意味着如果我有两个用于初始化的测试场景(这是理论的来源),我只能测试一个场景,因为第一个场景会使静态类处于不同的状态。
  • 不幸的是,这会很困难。通常,这是静态类的常见问题,尤其是当它们具有只应该调用一次的“初始化”方法时。不能测试的不仅仅是这个类。编写依赖于此代码的测试可能很困难。您可以创建一个实例类但确保只有一个实例吗?这是理想的解决方案。如果您使用的是IServiceCollection,则为services.AddSingleton<Whatever>(new Whatever()); 或类似名称。
  • 不可能具体使用实例类和容器,因为这个静态类是在容器构建阶段之前使用的。
  • 如果我们客观地看待这一点,我认为使用公开初始化方法的静态类没有设计问题。问题来自测试框架,它没有启用在新测试类实例中运行每个测试实例的选项,并且不共享静态上下文。该线程的目的是查看是否有办法在新的执行中运行每个测试实例,就像我要将这些测试拆分为两个不同的测试类一样。
  • 我考虑在另一个应用程序域中执行这些测试,但您甚至不能这样做。我认为它可以作为最后的手段,但事实并非如此。如果您必须对此进行测试,那么我能想到的只有“重置”方法。我只是不喜欢将它暴露给我的其余代码的想法。你可以做一些非常奇怪的事情,比如从 Initialize 方法返回一个 Guid,存储它,并要求 Reset 将其传回。这样,在生产代码中,如果超出范围,就无法检索它,因此不会被调用。但是..ugh.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-29
  • 1970-01-01
相关资源
最近更新 更多