如何为“T必须是引用类型”编写单元测试?

11

请考虑以下内容:

class MyClass<T> where T : class
{
}

在这种情况下,where子句正在执行一个规范,即MyClass只是引用类型的泛型。
理想情况下,我应该有一个单元测试来测试这个规范。然而,这个单元测试显然行不通,但它解释了我试图实现什么。
[Test]
[DoesNotCompile()]
public void T_must_be_a_reference_type()
{
    var test = new MyClass<int>();
}

我该如何测试一个只有在代码无法编译时才能实现的规格?

编辑

更多信息:好吧,我的做法是这样的(哈哈),我一直在遵循TDD方法论,在这种方法中,除非你有一个失败的单元测试,否则你不能编写任何代码。 假设你有这个:

class MyClass<T> { }

你能写一个测试,只有当T是一个类时才会失败吗?例如像default(T) == null这样的测试?
更进一步的编辑:
通过对此进行“根本原因分析”,问题在于我隐式地依赖于default(T)在该类的使用者中为null。我已经成功地将那个使用者代码重构到了另一个类中,并在那里指定了一个泛型类型限制(限制它为class),这有效地使得如果有人删除我上面所说的类的限制,那段代码就不能编译。

3
为什么你不进行单元测试以确保类的名称是“MyClass”? - SLaks
@SLaks:从技术上讲,var test = new MyClass<int>(); 会测试它,不是吗? - Scott Whitlock
我认为@SLaks是在使用讽刺来证明一个观点,即你不需要测试编译器...那是微软的工作。 - TheCloudlessSky
@TheCloudlessSky:我的观点是,如果你遵循TDD,你不会创建类,除非你已经编写了第一个单元测试,而这个单元测试只有在你使用不存在的类名时才能编译。因此,是的,你的第一个单元测试隐含地测试了类的名称。 - Scott Whitlock
4个回答

25
为什么需要对此进行单元测试?你会为这样的方法编写单元测试吗?
public void Foo(string x)

如何检查它只能接受字符串而不能是整数?如果不行,你认为有什么区别呢?

编辑:为了稍微不那么异想天开:在这种情况下,规范是由声明验证的。测试通常应该测试行为。这就是我喜欢代码合同的原因之一:除非它们表达了某些复杂的东西,否则我不觉得有必要对合同进行单元测试 - 在这种情况下,我将测试的是那个复杂性,而不是“强制执行合同”的部分。

编辑:回答问题编辑:

你可以写一个什么样的测试,只有当T是类时才会失败?

你可以写像这样的内容:

Type definition = typeof(MyClass<>);
Assert.Throws<ArgumentException>(() => definition.MakeGenericType(typeof(int)));

然而,这似乎违背了测试的真正目的...

嗯,我正在尝试让我的单元测试包含被测试单元的所有规格。 - Scott Whitlock
@Jon 很有趣,我们想到了完全相同的例子。 - vc 74
2
@Scott Whitlock - 但是仅仅代码编译通过就是你的测试。 - Pieter van Ginkel
6
@Scott: 我认为TDD不应该要求这样做。同样的,你不会编写一个测试来确保你不能传递无效的参数。你的测试驱动设计的积极方面(“我可以使用引用类型参数”),但不一定是消极方面。最终,所有的测试都应该是务实的 - 但在我看来,测试编译器并不是一个务实的时间利用方式。 - Jon Skeet
好的,你解释了为什么我不需要测试,并且还给了我一个可行的答案,+2 分给你! - Scott Whitlock

9

你不应该测试编译器是否正常工作。如果你在代码中指定了这些,那就足够了。从代码的角度来看,这与以下代码大致相同:

[Test]
public void Test_whether_add_works()
{
    int i = 1 + 2;

    Assert.AreEqual(3, i);
}

4
【测试】公共无返回值方法 Running1984() { 断言.AreEqual(5, 2 + 2); } - Dan Bryant

3
这是个很好的问题!非常同意您的测试驱动方法。您正在努力克服的是两种范式的冲突。旧的范式认为程序应该用数学证明它们是正确的,而无需运行它们(我们职业的祖先是数学家),而新的范式则认为程序应该通过执行示例用例(即测试)来证明其正确性。所以您即将尝试将新范式的实践应用于旧范式的产物,这当然不会真正奏效...
关于类型和测试的二元论,可以参考Chris Smith的这篇优秀文章:http://web.archive.org/web/20080822101209/http://www.pphsg.org/cdsmith/types.html

2

你是否在编写正确的单元测试?看起来你要测试的是C#编译器而不是你的代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接