NMock2.0 - 如何存根非接口调用?
我有一个类 API,它具有完整的代码覆盖率,并使用 DI 模拟完成所有工作的主类函数 (Job.Run) 中的所有逻辑。
我在生产中发现了一个错误,我们没有对其中一个数据输入字段进行验证。
因此,我添加了一个名为 ValidateFoo() 的存根函数...针对该函数编写了一个单元测试以期望出现 JobFailedException,运行测试 - 它显然失败了,因为该函数是空的。我添加了验证逻辑,现在测试通过了。
太好了,现在我们知道验证有效了。问题是 - 我如何编写测试以确保 ValidateFoo() 实际上在 Job.Run() 内部被调用? ValidateFoo() 是 Job 类的私有方法 - 所以它不是一个接口...
有没有办法用 NMock2.0 来做到这一点?我知道 TypeMock 支持非接口类型的伪造。但现在改变模拟库不是一个选择。此时,如果 NMock 无法支持它,我只需将 ValidateFoo() 调用添加到 Run() 方法并手动测试 - 考虑到我的 Job.Run() 方法有,显然我不想这样做目前覆盖率100%。有什么建议吗?非常感谢,非常感谢。
编辑:我想到的另一个选择是为我的 Job.Run 功能创建一个集成测试(向其注入复合对象的真实实现而不是模拟)。我将为该字段提供一个错误的输入值,然后验证作业是否失败。这有效并涵盖了我的测试 - 但它并不是真正的单元测试,而是测试一个功能单元的集成测试....嗯..
编辑2:有什么方法可以做到这一点吗?有人有想法吗?也许是 TypeMock——或者更好的设计?
I have a class API which has full code coverage and uses DI to mock out all the logic in the main class function (Job.Run) which does all the work.
I found a bug in production where we werent doing some validation on one of the data input fields.
So, I added a stub function called ValidateFoo()... Wrote a unit test against this function to Expect a JobFailedException, ran the test - it failed obviously because that function was empty. I added the validation logic, and now the test passes.
Great, now we know the validation works. Problem is - how do I write the test to make sure that ValidateFoo() is actually called inside Job.Run()? ValidateFoo() is a private method of the Job class - so it's not an interface...
Is there anyway to do this with NMock2.0? I know TypeMock supports fakes of non interface types. But changing mock libs right now is not an option. At this point if NMock can't support it, I will simply just add the ValidateFoo() call to the Run() method and test things manually - which obviously I'd prefer not to do considering my Job.Run() method has 100% coverage right now. Any Advice? Thanks very much it is appreciated.
EDIT: the other option I have in mind is to just create an integration test for my Job.Run functionality (injecting to it true implementations of the composite objects instead of mocks). I will give it a bad input value for that field and then validate that the job failed. This works and covers my test - but it's not really a unit test but instead an integration test that tests one unit of functionality.... hmm..
EDIT2: IS there any way to do tihs? Anyone have ideas? Maybe TypeMock - or a better design?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
NMock2的当前版本可以模拟具体类型(我不记得他们添加这个的确切版本,但我们使用的是版本 2.1),使用最熟悉的语法:
MockStyle.Transparent 指定任何您不存根或期望的内容都应该由底层实现处理 - 因此您可以存根并设置您所使用的实例上的方法的期望测试。
但是,您只能对公共方法(和属性)进行存根和设置期望,这些方法也必须是虚拟的或抽象的。因此,为了避免依赖集成测试,您有两个选择:
Job.ValidateFoo()
设为公共和虚拟。The current version of NMock2 can mock concrete types (I don't remember exactly which version they added this, but we're using version 2.1) using the mostly familiar syntax:
MockStyle.Transparent specifies that anything you don't stub or expect should be handled by the underlying implementation - so you can stub and set expectations for methods on an instance you're testing.
However, you can only stub and set expectations on public methods (and properties), which must also be virtual or abstract. So to avoid relying on integration testing, you have two options:
Job.ValidateFoo()
public and virtual.Job
.由于所有私有的都是由公共方法调用的(除非依赖反射运行时执行),那么这些私有就是由公共方法执行的。这些私有方法会导致对象发生更改,而不仅仅是执行代码,例如设置类字段或调用其他对象。我会找到一种方法来获取调用私有方法的“结果”。 (或者嘲笑不应该在私有方法中执行的事情。)
我看不到正在测试的类。另一个可能促使您想要访问私有方法的问题是,它是一个超级大的类,具有大量私有功能。这些类可能需要分解为更小的类,其中一些私有类可能会变成更简单的公共类。
Since all private are all called by public methods (unless relying on reflection runtime execution), then those privates are being executed by public methods. Those private methods are causing changes to the object beyond simply executing code, such as setting class fields or calling into other objects. I'd find a way to get at those "results" of calling the private method. (Or mocking the things that shouldn't be executed in the private methods.)
I can't see the class under test. Another problem that could be pushing you to want access to the private methods is that it's a super big class with a boatload of private functionality. These classes may need to be broken down into smaller classes, and some of those privates may turn into simpler publics.