不幸的是,我似乎无法在最小的工作示例中重现此行为,因此这可能过于模糊。但是,我至少可以说明不导致行为的原因。
我有一个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)();
}
我的期望是打电话:
rdmd --main -unittest tmp.d
将产生输出
Testing c1 func.
Testing class c1.
Testing c2 func.
它确实(c2 func的单元测试直到实例化时才运行)。
然而,在我类似但更长的D模块中,没有运行模板类c2对应单元的单元测试(我确保在我的其他单元测试中将print语句与此处相同)。
这有点令人担忧,事实上,我一直在依赖这些其他单元测试的正确性。此外,rdmd乐于接受单元测试代码中的语法错误,尽管从未运行过所述代码。
所以这是我可以排除的:
关于这里可能出现什么问题的任何想法?如果可以的话,我会提供一个MWE,但我写的每个版本似乎都能正常工作!
答案 0 :(得分: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);
}
在这种情况下,底部的单元测试将失败(因为assert(1 == 0)),因此模板类的单元测试永远不会运行。
当将模板类与单元测试一起使用时,这会带来一个主要问题。如果您的模板类失败会以某种方式破坏导致单元测试失败的单元测试,那么它自己的单元测试永远不会运行。在静默失败的情况下(模板类中的错误在我的代码中触发了静默退出),这将表现为模板类的测试从未运行。
摘要:DMD通常只按其出现的顺序运行单元测试。但是,由于模板类在没有完成模板的情况下不存在,因此模板类中的单元测试不会按它们出现的顺序运行。相反,它们在第一次单元测试之后立即运行(按顺序),其中模板类被实例化。
解决方法:在模板类的正下方添加一个单独的单元测试,只需要对所有要测试的类型进行实例化,这将导致以正确的顺序运行单元测试。但是,一个看似更好的策略是在实例化的测试块之前运行那些单元测试!