我一直是Python doctest库的粉丝,原因很简单,注释不仅有用,而且可用于断言正确的行为。我最近偶然发现了(貌似)鲜为人知的System.Diagnostics.ConditionalAttribute for .NET。这可以很容易地用于允许您在类本身内定义类方法的测试。这是一个简单的例子:
using System.Diagnostics;
using NUnit.Framework;
namespace ClassLibrary1
{
public class Class1
{
public static int AddTwoNumbers(int x, int y)
{
return x + y;
}
[Conditional("DEBUG")]
[TestCase(1, 1, 2)]
[TestCase(1, 2, 3)]
[TestCase(2, 1, 3)]
[TestCase(11, 7, 18)]
public static void TestAddTwoNumbers(int x, int y, int sum)
{
int actual = AddTwoNumbers(x, y);
Assert.AreEqual(sum, actual);
}
}
}
执行此操作,您可以创建一个调试程序集,该程序集将运行测试和生产程序集,并将其全部删除,类似于FAKE can build projects的方式。问题是,你呢?这是一个好习惯吗?为什么或为什么不呢?
你会进一步发现这个例子实际上并没有像我期望的那样工作。我不确定为什么该属性允许编译测试方法。关于为什么的任何想法?
答案 0 :(得分:4)
ConditionalAttribute
不会更改方法本身是否已编译。它会改变是否生成到方法的调用。
例如,Debug.WriteLine
已应用Conditional("DEBUG")
- 但代码仍然存在。关键是包含对Debug.WriteLine
的调用的 client 代码在没有定义DEBUG预处理器符号的情况下构建时将忽略这些调用。
要有条件地编译整个方法,您可以使用:
#if DEBUG
...
#endif
即使把它放在一边,我也不会自己做。我喜欢将生产代码与测试代码分开。我发现它更清晰 - 尽管它确实意味着我无法测试私有方法。 (有些人说你永远不应该测试实现细节,但那是一个完全不同的问题。)
还有针对真实代码进行测试的问题。如果您要构建一个版本的代码,其中包含内置测试而没有内置测试,并且您在生产中使用非测试程序集,则意味着您正在运行尚未测试的代码。当然,它可能与DEBUG定义的方式相同......但是如果不是这样的话呢?我喜欢能够针对完全相同的二进制文件运行单元测试,然后在生产中使用。
答案 1 :(得分:2)
(IMO)绝对不是。
虽然使用Debug
属性将使方法不会在您的发布项目中公开,但事实是在开发时(将在DEBUG模式下,很可能),这将污染根据您开发的测试用例数量(并且您可以开发许多测试用例,即使对于占用空间小的类),也可以上课。
另外,我认为它的封装很差。您正在寻找为类编写测试,这些测试实际上无助于提供或增强类的实际功能,因此,不应该是它的一部分。
最后,单独测试工具的一大优势是,您可以在多个类之间设置复杂的相互依赖关系,允许您测试这些类之间的交互。
在您的情况下,愿景的范围是一个单一的类。如果你需要引入其他类(模拟实现等)那么你会把它们放进去吗?
答案 2 :(得分:2)
这种方法会有利有弊。
一方面,您将能够测试内部。有些人会认为这是件好事。其他人会争辩说你应该只测试公共接口。就个人而言,我认为偶尔需要测试内部(如果没有其他原因而不是隔离特定行为),但这是你可以用InternalsVisibleTo实现的。
另一方面,您将能够测试内部。您的测试代码的行为就像它属于程序集一样。我个人认为它不是申请的一部分,不应该在那里。将其视为“关注点分离”的一种形式。测试测试,应用程序执行测试测试的事情。但是测试应该尽可能少地了解实现细节。如果测试是在内部,那么他们很容易知道所有细节。如果稍后更改实现细节,则测试将失效并且必须重写。
就个人而言,我更喜欢外部装配。它不仅强制执行我的测试只测试软件的概念,而且它让我问自己如何编写软件,以便它可以由外部源测试。这导致整体软件设计更好。我还没后悔。
答案 3 :(得分:0)
我同意其他大多数答案:最好将单元测试分开。特别注意Jon关于ConditionalAttribute
如何工作的观点:特别是代码仍然在那里,它只是没有被调用。
但是,我想你想Code Contracts。它们实际上使用了重写器,在编译后修改代码。这允许您轻松设置包含所有类型的运行时检查的Debug构建以及没有任何代码的Release构建。您还可以安装VS扩展,在代码编辑器中显示前置和后置条件作为弹出窗口。
我的博客上有一个简短的getting started post,我在其中为图书馆设置CC。我的风格是拥有一个Debug构建(带有完整检查)和一个Release构建(没有检查,但包含一个包含前置条件的单独dll)。
请注意,代码合同不是单元测试的替换,但它是一个很好的补充。