如何使用最小起订量测试调用受保护助手的代码
我目前运行的测试如下所示:
// In Blah.cs
public class ClassUnderTest
{
public bool MethodUnderTest()
{
// Do a bunch of stuff...
return HelperMethod();
}
protected virtual bool HelperMethod()
{
bool success = false;
// Proprietary Hardware Access.
// Database Calls.
// File System Modifications.
return success;
}
}
// In TestBlah.cs
public class TestStub : ClassUnderTest
{
public bool HelperMethodReturnValue;
protected override bool HelperMethod()
{
return HelperMethodReturnValue;
}
}
[TestClass]
public class TestingClass
{
[TestMethod]
public void ClassUnderTest_MethodUnderTest_TestHelperReturnsTrue()
{
var stub = new TestStub();
stub.HelperMethodReturnValue = true;
Assert.IsTrue(stub.MethodUnderTest());
}
[TestMethod]
public void ClassUnderTest_MethodUnderTest_TestHelperReturnsFalse()
{
var stub = new TestStub();
stub.HelperMethodReturnValue = false;
Assert.IsFalse(stub.MethodUnderTest());
}
}
上面的测试对于简单的事情来说看起来不错,但是存根类会迅速变得指数级更大且更复杂。 我想使用 Moq 替换存根类。但是,这不会编译,因为由于某种原因我无法在受保护的方法上设置返回值。
[TestMethod]
public void ClassUnderTest_MethodUnderTest_TestHelperReturnsFalse()
{
var mockClass = new Mock<ClassUnderTest>();
mockClass.Protected().Setup("HelperMethod").Returns(false);
Assert.IsFalse(mockClass.Object.MethodUnderTest());
}
有人知道我该怎么做吗?我可以用最小起订量做到这一点吗?
I currently run tests that look like the following:
// In Blah.cs
public class ClassUnderTest
{
public bool MethodUnderTest()
{
// Do a bunch of stuff...
return HelperMethod();
}
protected virtual bool HelperMethod()
{
bool success = false;
// Proprietary Hardware Access.
// Database Calls.
// File System Modifications.
return success;
}
}
// In TestBlah.cs
public class TestStub : ClassUnderTest
{
public bool HelperMethodReturnValue;
protected override bool HelperMethod()
{
return HelperMethodReturnValue;
}
}
[TestClass]
public class TestingClass
{
[TestMethod]
public void ClassUnderTest_MethodUnderTest_TestHelperReturnsTrue()
{
var stub = new TestStub();
stub.HelperMethodReturnValue = true;
Assert.IsTrue(stub.MethodUnderTest());
}
[TestMethod]
public void ClassUnderTest_MethodUnderTest_TestHelperReturnsFalse()
{
var stub = new TestStub();
stub.HelperMethodReturnValue = false;
Assert.IsFalse(stub.MethodUnderTest());
}
}
The above looks fine for simple things, however the stub class gets exponentially bigger and more complex quickly.
I'd like to replace the stub class using Moq. However this won't compile because for some reason I can't set a return value on a protected method.
[TestMethod]
public void ClassUnderTest_MethodUnderTest_TestHelperReturnsFalse()
{
var mockClass = new Mock<ClassUnderTest>();
mockClass.Protected().Setup("HelperMethod").Returns(false);
Assert.IsFalse(mockClass.Object.MethodUnderTest());
}
Anyone know how I'd go about doing this? Can I do this with moq?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
查看moq源代码我'我猜您需要显式调用安装程序的通用版本。非泛型版本似乎用于 void 方法。所以尝试
除此之外,我建议重新考虑你的类设计。如果 HelperMethod() 正在做这么多事情,那么值得将其自己的类作为依赖项注入到 ClassUnderTest 中。测试模拟对象,而不是使用模拟对象来测试“真实”的东西,不是模拟框架的目的(至少不是首先)。
Looking at the moq source code I'd guess you need to explicitly call the generic version of Setup. The non-generic version seems to be used for void methods. So try
Beside this, I'd recommend re-thinking your class design. If HelperMethod() is doing such a bunch of things it would be worth its own class that is injected as a dependency into ClassUnderTest. Testing a mock object, instead of using a mock object to test something "real", is not what mocking frameworks are made for (not in the first place, at least).
受保护的方法并不是隔离依赖项的好方法,但它有时会出现,特别是在调整遗留代码以实现可测试性时。避免基于字符串的 Moq 语法的尴尬的一种选择是使方法“受保护的内部”(或者只是“内部”,如果您不打算在其他程序集的正常使用中覆盖它)。然后,您可以在程序集上使用 InternalsVisibleTo公开该方法。这有点像黑客,但为此目的使用受保护的方法已经有点像黑客了。在某些方面,我更喜欢“内部”方法,因为它清楚地表明这是您不应该使用的后门方法(测试除外),而不是您可能希望在正常情况下覆盖的受保护方法用法。
Protected methods are not a great way of isolating dependencies, but it does sometimes come up, particularly when adapting legacy code for testability. One option that avoids the awkward string-based Moq syntax is to make the method 'protected internal' (or just 'internal' if you don't intend to override it in normal usage from other assemblies.) You then use InternalsVisibleTo on the assembly to expose the method. This is a bit of a hack, but using a protected method for this purpose is already a bit of a hack. In some ways I prefer the 'internal' approach, as it makes it clear that this is a backdoor method that you're not supposed to use (except for testing), as opposed to a protected method that you might expect to override in normal usage.