模板别名导致单元测试失败

时间:2016-03-10 09:13:59

标签: unit-testing templates d

我是一个新面孔的D新手,我非常有兴趣利用它所提供的一切。我目前正在将用C ++编写的大型代码库转换为D用于教育。我几乎没有开始,我达到了一些奇怪的不一致。我有一个带有构造函数的模板结构和该构造函数的unittest,(希望我正确使用它)。它似乎正确验证。但是,如果我在文件底部为特定的模板化结构创建一个类型别名,我会在unittest中得到一个异常。

main.d

import math;

int main() {

    return 0;
}

math.d

import std.math;
import std.stdio;

struct Vector2(T) {
    T[2] vec = [0, 0];

    @property const T x() {return vec[0];}
    @property inout(T) x(inout(T) val) {return vec[0] = val;}
    @property const T y() {return vec[1];}
    @property inout(T) y(inout(T) val) {return vec[1] = val;}

    this(T x, T y) {
        this.x = x;
        this.y = y;
    }
    unittest {
        Vector2!int a = Vector2!int(2, 2);
        assert(a.x == 2 && a.y == 2);

        Vector2!float b = Vector2!float(2.2, 2.2);
        assert(b.x == 2.2 && b.y == 2.2);  // <-- this line excepts given alias
    }
}

// if this is not here, no problem.
// if it is here "core.exception.AssertError@math.d(21): unittest failure"
alias Vector2f = Vector2!float;

为什么别名的存在会导致单元测试失败?我正在使用此命令来构建:

dmd -unittest main.d math.d

我使用Windows 10,DMD版本2.070.2和msys2 shell

2 个答案:

答案 0 :(得分:3)

  1. 模板本身不是(并且通常不能)单元测试。只有它的实例化实例是。

  2. 由于2.2无法在浮点变量中准确表示,因此距离double最近的2.2与距{最近的float不同{1}}。如果将行更改为以下(2.2是浮点常量,2.2f是双常量),则测试成功就好了:

    2.2
  3. 通常,除非really know what they are doing,否则应避免直接比较浮点变量。在D中,可能需要使用std.math.approxEqual来比较它们。

答案 1 :(得分:3)

如果模板没有实例化,模板甚至不会被编译到某些基本语法检查之外。模板类型是类型的模板,而不是实际类型。因此,Vector2不是类型,而Vector2!int是。{1}}。您向Vector2!float声明别名的事实是实例化Vector2并使其完全编译 - 包括unittest块。如果模板没有实例化,模板内部的unittest块不会比模板的其余部分编译,并且它将被编译到模板的每个实例中(这就是为什么它&#39} ;将unittest块放在模板中通常不是一个好主意。

因此,至少应该在模​​板之外放置一个unittest块来实例化模板。如果你想避免将单元测试编译到模板的每个实例中,那么你应该将它们全部移出模板之外(可能标记为注释以指示它们使用哪些函数),这将使模板适当实例化和测试。如果你不关心在模板的每个实例化中获得单元测试的副本,并且想要在他们测试的函数之后立即离开测试(就像你通常那样),那么你只需要放一个{ {1}}阻塞模板后立即实例化它,以便模板内的unittest块被编译并运行。

a proposal用于添加功能以允许模板内部的特殊unittest块,这些块实际上不是模板的一部分,并且功能类似于模板外的unittest块功能(但仍然会在被测试的功能旁边),但尚未确定它是否会添加到语言中以解决此问题。因此,在此期间,我建议不要在模板中放置unittest块,但无论如何,您需要确保模板在其自身之外进行实例化,以便对其进行编译和测试。

在旁注中,您真的不应该将浮点值与unittest==进行比较,如本经典论文中所述:http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html。使用approxEqual将是一个更好的选择。