我想知道如何正确使用NUnit。首先,我创建了一个单独的测试项目,并将我的主要项目作为引用使用。但是,在这种情况下,我无法测试私有方法。我的猜测是我需要将我的测试代码包含到我的主代码中?! - 那似乎不是正确的做法。(我不喜欢在代码中嵌入测试的想法。)
如何使用NUnit测试私有方法?
我想知道如何正确使用NUnit。首先,我创建了一个单独的测试项目,并将我的主要项目作为引用使用。但是,在这种情况下,我无法测试私有方法。我的猜测是我需要将我的测试代码包含到我的主代码中?! - 那似乎不是正确的做法。(我不喜欢在代码中嵌入测试的想法。)
如何使用NUnit测试私有方法?
尽管我认为单元测试的重点应该是公共接口,但如果您也测试私有方法,您将更加深入地了解您的代码。 MS测试框架通过使用PrivateObject和PrivateType允许这样做,而NUnit则不允许。我的做法是:
private MethodInfo GetMethod(string methodName)
{
if (string.IsNullOrWhiteSpace(methodName))
Assert.Fail("methodName cannot be null or whitespace");
var method = this.objectUnderTest.GetType()
.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
if (method == null)
Assert.Fail(string.Format("{0} method not found", methodName));
return method;
}
这种方式意味着您无需为了可测试性而牺牲封装性。请注意,如果您想测试私有静态方法,则需要修改您的BindingFlags。上面的示例仅适用于实例方法。
一般来说,单元测试关注类的公共接口,认为实现是无关紧要的,只要从客户的角度看结果正确即可。
因此,NUnit不提供测试非公开成员的机制。
System.Reflection
允许您使用绑定标志访问和调用非公共方法,因此您可以对 NUnit 进行黑客攻击或设置自己的框架。或者(我认为更容易的方法),您可以设置编译时标志(#if TESTING
)来更改访问修饰符,从而可以使用现有的框架。 - harpo编写单元测试的常见模式是只测试公共方法。
如果您发现有许多私有方法需要测试,通常这表明您应该重构代码。
将这些方法在当前所在类上设置为公共方法是错误的。这会破坏您希望该类具有的契约。
将它们移到助手类并在那里设置为公共方法可能是正确的做法。此类可能不会被您的 API 公开暴露。
这样测试代码就永远不会与您的公共代码混合。
类似的问题是测试私有类,即您不从程序集导出的类。在这种情况下,可以使用属性 InternalsVisibleTo 显式地使您的测试代码程序集成为生产代码程序集的友元。
通过将你的测试程序集声明为目标程序集的友元程序集,可以测试私有方法。请参考下面链接了解详细信息:
http://msdn.microsoft.com/en-us/library/0tke9fxk.aspx
这种方法很有用,因为它基本上将测试代码与生产代码分开。我自己从未使用过这种方法,因为我从未觉得有需要。我想你可以使用它来尝试并测试极端案例,这些案例无法在测试环境中复制,以了解你的代码如何处理它。
正如先前所说,你确实不应该需要测试私有方法。你更有可能想将代码重构为较小的构建块。一个可能有帮助的提示是,尝试考虑系统相关的领域,并思考居住在这个领域的“真实”对象。你系统中的对象/类应直接与真实对象相关联,从而使你能够隔离对象应包含的确切行为,并限制对象的责任。这将意味着你是在逻辑上进行重构,而不仅仅是为了测试特定方法而进行重构;你将能够测试对象的行为。
如果你仍然感觉需要测试内部方法,你可能还需要在测试中考虑模拟,因为你可能想要专注于一段代码。模拟是将对象的依赖项注入其中,但注入的对象不是“真实”或生产对象。它们是带有硬编码行为的虚假对象,以更容易地隔离行为错误。Rhino.Mocks是一种流行的免费模拟框架,它将基本上为你编写对象。TypeMock.NET(一个带有社区版的商业产品)是一种更强大的框架,可以模拟CLR对象。当测试数据库应用程序时,对于模拟SqlConnection/SqlCommand和Datatable类非常有用。
希望这个答案能给你更多有关单元测试的信息,并帮助你从单元测试中获得更好的结果。
我支持测试私有方法的能力。当xUnit开始时,它旨在测试代码编写后的功能。测试接口对于这个目的来说已经足够了。
单元测试已经发展到测试驱动开发。拥有测试所有方法的能力对于这个应用程序是有用的。
#if DEBUG
...test code...
#endif
这里所说的“block”意味着a)它未在发布中分发,并且 b)我可以使用internal
/ Friend
级别声明而无需进行额外操作。
更为重要的是,它提供了使用partial
类的机会,可以用于创建代理以测试私有方法。例如,要测试返回整数值的私有方法:
public partial class TheClassBeingTested
{
private int TheMethodToBeTested() { return -1; }
}
#if DEBUG
using NUnit.Framework;
public partial class TheClassBeingTested
{
internal int NUnit_TheMethodToBeTested()
{
return TheMethodToBeTested();
}
}
[TestFixture]
public class ClassTests
{
[Test]
public void TestMethod()
{
var tc = new TheClassBeingTested();
Assert.That(tc.NUnit_TheMethodToBeTested(), Is.EqualTo(-1));
}
}
#endif
如果这个回答没有解决问题,那么使用反射、#if #endif语句或使私有方法可见等解决方案并不能解决问题。不将私有方法公开可能有几个原因...例如,如果它是生产代码,并且团队正在回顾性地编写单元测试。
对于我正在工作的项目,只有MSTest(遗憾的是)似乎有一种方法,使用访问器来单元测试私有方法。
你不要测试私有函数。
有方法可以使用反射来获取私有方法和属性。但这并不容易,我强烈不建议这种做法。
你根本不应该测试任何非公共的东西。
如果你有一些内部方法和属性,你应该考虑将其改为公共的,或者将测试与应用程序一起发布(我认为这不是一个问题)。
如果你的客户能够运行测试套件并看到所提供的代码实际上是“工作的”,我不认为这是一个问题(只要你不通过此方式泄露你的知识产权)。我在每个版本中包含的内容是测试报告和代码覆盖率报告。
public class SomeClass
{
protected int SomeMethod() {}
}
[TestFixture]
public class TestClass : SomeClass{
protected void SomeMethod2() {}
[Test]
public void SomeMethodTest() { SomeMethod2(); }
}
Message: Method is not public
。 - Gucu112