我的单元测试 class 可以跟踪测试执行吗

Can my unit test class keep track of test execution

我们的代码在 List<Rule> 集合中定义了一些“规则”。每个规则都包含一些字符串形式的逻辑。规则连同一些数据一起传递给“规则引擎”。规则引擎依次根据规则评估数据,直到找到评估为真的规则,然后 returns Rule.

我们想要自动测试每个规则。这些测试实际上是集成测试,而不是单元测试,因为它们将测试规则引擎和规则的组合。

如何编写一个测试“确保每个规则在至少一个单元测试中评估为真”?

我想出了一种方法来 运行 在所有测试都具有 运行(参见 https://xunit.github.io/docs/shared-context.html#class-fixture)之后,一些夹具拆卸代码,并通过使用静态变量来记录评估规则我可以​​在拆解期间检查是否所有规则都已在单元测试期间返回。但是这种方法有不良影响,它会导致单个测试报告为失败(在拆卸中),但实际上并没有失败。

TLDR:控制测试顺序。由于这些是集成测试,所以这不是最大的禁忌——如果它们是单元测试,那将是最大的禁忌。

我发现通过使用静态变量来记录评估为真的规则,并确保最后 have-all-rules-evaluated-as-true 测试,因为根据这里的建议 https://hamidmosalla.com/2018/08/16/xunit-control-the-test-execution-order/,实现我需要的东西变得轻而易举。

万一 link 死了,这里是实现这个方法的方法

首先,创建一个 AlphabeticalOrderer 实现 xUnit 的 ITestCaseOrderer:

public class AlphabeticalOrderer : ITestCaseOrderer
{
    public IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases)
            where TTestCase : ITestCase
    {
        var result = testCases.ToList();
        result.Sort((x, y) => StringComparer.OrdinalIgnoreCase.Compare(x.TestMethod.Method.Name, y.TestMethod.Method.Name));
        return result;
    }
}

然后在你的测试中使用新创建的属性class,并创建一个静态变量来记录进度:

[TestCaseOrderer("MyCompany.AlphabeticalOrderer", "MyTestsDLL")]
public class RulesTests
{
    private static List<Rule> _untestedRules;

    public RulesTests()
    {
        if (_untestedRules == null) // this will run once per [Fact]
        {
            _untestedRules = <some way of getting all the rules> // this will only run first time around
        }
    }

每次触发规则时,记录是哪条规则:

    private void MarkRuleAsTested(LendingRule testedRule)
    {
        var rulesToRemove = _untestedRules.Where(r => r.Logic == testedRule.Logic).ToList();

        foreach (var ruleToRemove in rulesToRemove)
        {
            _untestedRules.Remove(ruleToRemove);
        }
    }

然后到运行的最后一个测试应该检查集合:

    [Fact]
    public void ZZ_check_all_rules_have_been_triggered_by_other_tests()
    {
        // This test must run last because it validates that the
        // OTHER tests taken together have resulted in each rule
        // being evaluated as true at least once.
        if (!_untestedRules.Any())
        {
            return;
        }

        var separator = "\r\n------------------------\r\n";
        var untestedRules = string.Join(separator, _untestedRules.Select(ur => $"Logic: {ur.Logic}"));
        throw new SomeRulesUntestedException($"The following rules have not been tested to resolve as True: {separator}{untestedRules}{separator}");
    }

这会导致可读性很好的测试失败。

您同样可以从 _testedRules 的空静态集合开始,最后将该集合与完整的规则集进行比较。