为什么rdmd不能运行所有单元测试?

Joh*_*tte 5 unit-testing d dmd

不幸的是,我似乎无法在最小的工作示例中重现此行为,因此这可能过于模糊.但是,我至少可以说明不会导致这种行为的原因.

我有一个D模块,包含几个带有单元测试的类,其结构类似于:

import std.stdio;

class c1{
        int c1func(int blah){ return blah; }
        unittest{
                writeln("Testing c1 func.");
                stdout.flush();
        }
}

class c2(T:c3) : c1{
        private static int c2func(int blah){ return blah; }
        unittest{
                writeln("Testing c2 func.");
                stdout.flush();
        }

        int c2fun2(int blah){
                T tmp = new T();
                return tmp.c3fun(blah);
        }
}

class c3{
        abstract int c3fun(int blah);
}

class c4 : c3{
        override int c3fun(int blah){ return blah; }
}

unittest{
        writeln("Testing class c1.");
        stdout.flush();
        c1 myc2 = new c2!(c4)();
}
Run Code Online (Sandbox Code Playgroud)

我的期望是打电话:

rdmd --main -unittest tmp.d
Run Code Online (Sandbox Code Playgroud)

会产生输出

Testing c1 func.
Testing class c1.
Testing c2 func.
Run Code Online (Sandbox Code Playgroud)

它确实(c2 func的单元测试直到实例化时才运行).

但是,在我类似的,但更长的D模块中,没有运行模板类c2的对应单元的单元测试(我确保在我的其他单元测试中将print语句与此处相同).

这有点令人担忧,事实上,我一直依赖这些其他单元测试的正确性.此外,尽管从未运行过所述代码,但rdmd很乐意接受单元测试代码中的语法错误.

所以这是我可以排除的:

  • rdmd正在读取单元测试.
  • rdmd实际上是针对该文件的最新版本运行的.
  • rdmd显然很乐意为模板类的实现运行单元测试,即使它们的参数有抽象类的特化,只要这些模板类实际上是实例化的.
  • 我的模板类中的函数(类似于示例代码中的c2)实际上是在底部的主单元测试块中调用的,因此模板类已经被实例化了.
  • rdmd本身没有错,因为使用dmd编译并且相同的标志也无法运行这些单元测试.

关于这里可能出现什么问题的任何想法?如果可以的话,我会提供一个MWE,但我写的每一个版本似乎都运行正常!

Joh*_*tte 3

这似乎是 rdmd 订购单元测试的方式造成的,这与我预期的方式不同。

看起来 RDMD 不是在实例化时调用实例化模板类的单元测试,而是在实例化类的单元测试完成后立即调用。

这是一个 MWE:

import std.stdio;

class c1{
        int c1func(int blah){ return blah; }
        unittest{
                writeln("Testing c1 func.");
                stdout.flush();
        }
}

class c2(T:c3) : c1{
        private static int c2func(int blah){ return blah; }
        unittest{
                writeln("Testing c2 func.");
                stdout.flush();
        }

        int c2fun2(int blah){
                T tmp = new T();
                return tmp.c3fun(blah);
        }
}

class c3{
        abstract int c3fun(int blah);
}

class c4 : c3{
        override int c3fun(int blah){ return blah; }
}

unittest{
        writeln("Testing class c1.");
        stdout.flush();
        c1 myc2 = new c2!(c4)();
        assert(1==0);
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,底部的单元测试将失败(因为assert(1==0)),因此模板类的单元测试永远不会运行。

当将模板类与单元测试一起使用时,这会带来一个主要问题。如果您的模板类失败以某种方式被破坏,导致实例化它的单元测试失败,那么它自己的单元测试永远不会运行。在静默失败的情况下(模板类中的错误在我的代码中触发了静默退出),这将表现为模板类的测试从未运行。

摘要:DMD 通常只是按照单元测试出现的顺序运行单元测试。但是,由于模板类在未完成模板的情况下不存在,因此模板类内的单元测试不会按照它们出现的顺序运行。相反,它们在实例化模板类的第一个单元测试之后立即运行(按顺序)。

解决方法:在模板类正下方添加一个单独的单元测试,该模板类仅使用要测试的所有类型实例化它,这将导致单元测试以正确的顺序运行。然而,一个看似更好的策略是在实例化发生的测试块之前运行这些单元测试!