单元测试构造函数是否重要?

时间:2008-12-10 23:06:09

标签: c# .net unit-testing constructor

我应该对单元测试构造函数吗?说我有这样的构造函数:

IMapinfoWrapper wrapper;
public SystemInfo(IMapinfoWrapper mapinfoWrapper)
{
    this.wrapper = mapinfoWrapper;
}

我是否需要为这位建筑师编写单元测试?我没有包装器变量的任何getter,所以我不需要测试它。

15 个答案:

答案 0 :(得分:91)

单元测试是关于测试对象的公共状态,行为和交互。

如果你只是在构造函数中设置一个私有字段,那么测试什么呢?

不要打扰单元测试简单的访问器和更改器。那太傻了,对任何人都没有帮助。

答案 1 :(得分:34)

是。如果构造函数中有逻辑,则应测试它。简单地设置属性不是逻辑IMO。条件,控制流等IS逻辑。

修改 您应该测试IMapinfoWrapper何时为null,如果需要该依赖项。如果是这样,那么这就是逻辑,你应该有一个测试来捕获你的ArgumentNullException或者其他......你的测试是定义代码行为方式的规范。如果它抛出ArgumentNullException,那么应该在测试中指定。

答案 2 :(得分:13)

问:如果您在构造函数中设置成员变量,为什么要设置它。

答:因为你有一个失败的单元测试,只能通过在构造函数中设置它来传递。

如果您使用此逻辑,只编写代码以使单元测试通过(测试驱动开发),那么您已经有了问题的答案。

答案 3 :(得分:8)

没有。它的功能将通过课堂上的每个其他单元测试进行测试。

答案 4 :(得分:6)

你绝对应该测试构造函数。如果您有默认构造函数,则应测试是否可以调用它。如果稍后更改类会怎么样 - 也许它会变成单例或删除默认构造函数而不是需要参数?在这种情况下,测试应该失败以警告该更改(以便可以修复类或测试以满足新的要求)。

默认构造函数的存在是应该进行测试的要求。即使所有构造函数都设置了将在其他地方测试的私有成员,也应测试存在无参数构造函数的事实。

答案 5 :(得分:4)

我在测试构造函数时包含逻辑 - 例如验证或条件设置私人州。验证错误最终在构造函数抛出的异常中结束。成功执行最终会创建一个对象,该对象根据构造函数中设置的状态显示特定的行为。 无论哪种方式,都需要测试。但构造函数测试很无聊,因为它们看起来都一样 - 调用构造函数,进行断言。测试方法声明通常占用比整个测试逻辑更多的空间......所以我写了一个简单的测试库,它有助于为构造函数编写声明性测试:How to Easily Test Validation Logic in Constructors in C#

这是一个例子,我在一个类的构造函数上尝试七个测试用例:

[TestMethod]
public void Constructor_FullTest()
{

    IDrawingContext context = new Mock<IDrawingContext>().Object; 

    ConstructorTests<Frame>
        .For(typeof(int), typeof(int), typeof(IDrawingContext))
        .Fail(new object[] { -3, 5, context }, typeof(ArgumentException), "Negative  length")
        .Fail(new object[] { 0, 5, context }, typeof(ArgumentException), "Zero length")
        .Fail(new object[] { 5, -3, context }, typeof(ArgumentException), "Negative width")
        .Fail(new object[] { 5, 0, context }, typeof(ArgumentException), "Zero width")
        .Fail(new object[] { 5, 5, null }, typeof(ArgumentNullException), "Null drawing context")
        .Succeed(new object[] { 1, 1, context }, "Small positive length and width")
        .Succeed(new object[] { 3, 4, context }, "Larger positive length and width")
        .Assert();

}

通过这种方式,我可以测试构造函数的所有相关案例,而无需输入太多内容。

答案 6 :(得分:3)

在许多受FDA监管的环境中,更严格的代码必须经过100%的测试......包括类的构建。因此,无论是否进行测试,都需要对构造函数进行测试。此外,使用静态分析工具的公司需要确保正确初始化类的所有数据成员,以便不会出现错误,尽管代码可以顺利运行且没有错误。通常数据成员初始化是在构造函数中完成的......只是值得深思。

答案 7 :(得分:3)

取决于。

我不打算为你给出的例子这么简单的东西写一个专门的构造函数测试。

但是,如果你在构造函数中有逻辑测试,比如参数验证,那么肯定是。虽然像原始海报一样,如果可能,我在构造函数中不起作用,但通常必须进行参数验证。在这种情况下,不可避免地使构造函数执行某些工作。如果构造函数中存在逻辑,那么它总是存在错误的可能性,因此我就像任何其他方法调用一样对待它并对其进行适当的测试。

答案 8 :(得分:1)

我相信100%的报道。此外,100%的覆盖范围不仅仅是通过模拟事物或只是设置和获取事物来测试简单的交互,而是通过检查功能的更多集成/验收测试。因此,如果您最终编写了非常好的集成/验收测试,则应调用所有构造函数(以及诸如setter和getter之类的简单方法)。

答案 9 :(得分:1)

除非开发人员确保不能更改状态逻辑,否则还必须测试访问器和更改器。例如,如果使用Singleton的设计模式,通常会使用访问器或属性,如果未初始化类,则由访问器完成,因为构造函数是私有的。在C ++中,可以使其函数为const或static,其中类的数据成员不能更改。 (注意:即使使用静态也有点风险,因为这些变量通常是全局的。)但是,如果没有测试,如果有人未能使用预防措施,您如何能够100%准确地保证所写的内容不会成为故障时间?维护难以万无一失。

答案 10 :(得分:1)

我认为答案是肯定的。

有很多代码可以假设一个初始化的对象状态,而不是空引用 - 通常在构造函数中没有指定显式值时。

我很高兴在初始化的公共成员值被更改时,构造函数测试会中断以提醒我。这是关于防御性测试 - 我是务实的,并且更乐于接受测试,并且当它们被证明没有帮助或有用时将它们移除。

答案 11 :(得分:0)

SystemInfo实例的哪些行为取决于wrapper

的值

如果出现任何问题(例如空值导致破损),那么我建议编写描述每种情况的场景,并使用它们来推动相应单元测试的定义。

如果所有场景最终都依赖于IMapinfoWrapper私有实例的状态或行为,那么我建议改为在该类上编写单元测试。

答案 12 :(得分:0)

除非您正在编写编译器,否则您只会测试编译器是否可以生成用于执行分配的代码,这通常是没有意义的。

现在,在更常见的情况下,如果你想用包装器做其他事情,那么也许有一点。例如,如果您尝试传递null,则可以抛出ArgumentNullException,理论上,可以进行单元测试。即使这样,测试的价值也很小。

就个人而言,我几乎从不明确地测试构造函数。如果它们足够复杂以至于需要测试,我倾向于觉得代码有点臭了。

答案 13 :(得分:0)

如果构造函数包含一些逻辑,比如初始化一个类,我想你应该测试一下构造函数。或者你可以和开发人员讨论在构造函数中放置初始化会降低测试代码的可测试性。

答案 14 :(得分:-1)

单元测试是关于检查执行路径,通常称为Cyclomatic Complexity

如果你没有可供选择的路径,没有if,没有循环,没有GOTO(= P)它不是很有用