简体   繁体   English

TDD和嘲弄

[英]TDD and mocking

First of all, I have to say, I'm new to mocking. 首先,我不得不说,我是嘲笑的新手。 So maybe I'm missing a point. 所以也许我错过了一点。

I'm also just starting to get used to the TDD approach. 我也刚刚开始习惯TDD方法。

So, in my actual project I'm working on a class in the business layer, while the data layer has yet to be deployed. 因此,在我的实际项目中,我正在处理业务层中的类,而数据层尚未部署。 I thought, this would be a good time to get started with mocking. 我想,这是开始嘲笑的好时机。 I'm using Rhino Mocks, but I've come to the problem of needing to know the implementation details of a class before writing the class itself. 我正在使用Rhino Mocks,但我在编写类本身之前遇到了需要知道类的实现细节的问题。

Rhino Mocks checks if alle the methods expected to be called are actually called. Rhino Mocks检查是否实际调用了预期调用的方法。 So I often need to know which mocked method is being called by the tested method first, even though they could be called in any order. 所以我经常需要知道测试方法首先调用哪个模拟方法,即使它们可以按任何顺序调用。 Because of that I'm often writing complicated methods before I test them, because then I know already in which order the methods are being called. 因为我在测试之前经常编写复杂的方法,因为我知道已经按照调用方法的顺序。

simple example: 简单的例子:

public void CreateAandB(bool arg1, bool arg2) {
    if(arg1)
        daoA.Create();
    else throw new exception;
    if(arg2)
        daoB.Create();
    else throw new exception;
}

if I want to test the error handling of this method, I'd have to know which method is being called first. 如果我想测试这个方法的错误处理,我必须知道首先调用哪个方法。 But I don't want to be bugged about implementation details when writing the test first. 但我不想在编写测试时先了解实现细节。

Am I missing something? 我错过了什么吗?

You have 2 choices. 你有2个选择。 If the method should result in some change in your class the you can test the results of your method instead. 如果该方法应该导致您的类中的某些更改,您可以测试您的方法的结果 So can you call CreateAandB(true,false) then then call some other method to see if the correct thing was created. 那么你可以调用CreateAandB(true,false)然后调用其他方法来查看是否创建了正确的东西。 In this situation your mock objects will probably be stubs which just provide some data. 在这种情况下,您的模拟对象可能是只提供一些数据的存根。

If the doaA and doaB are objects which are injected into your class that actually create data in the DB or similar, which you can't verify the results of in the test, then you want to test the interaction with them, in which case you create the mocks and set the expectations, then call the method and verify that the expectations are met. 如果doaAdoaB是注入到您的类中的实际创建数据库或类似数据的对象,您无法验证测试中的结果,那么您希望测试与它们的交互,在这种情况下,您创建模拟并设置期望,然后调用方法并验证是否满足期望。 In this situation your mock objects will be mocks and will verify the expected behaviour. 在这种情况下,您的模拟对象将是模拟并将验证预期的行为。

Yes you are testing implementation details, but your are testing the details of if your method is using its dependencies correctly, which is what you want to test, not how it is using them, which are the details you are not really interested in. 是的,你正在测试的实施细节,但你正在测试,如果你的方法正确使用它的依赖,这是你想要的测试,它不是如何使用它们,这是你是不是真正感兴趣的细节的细节。

EDIT 编辑

IDao daoA = MockRepository.GenerateMock<IDao>(); //create mock
daoA.Expect(dao=>dao.Create); //set expectation

...

daoA.VerifyExpectations(); //check that the Create method was called

you can ensure that the expectations happen in a certain order, but not using the AAA syntax I believe ( source from 2009 , might have changed since, EDIT see here for an option which might work ), but it seems someone has developed an approach which might allow this here . 您可以确保期望按照特定顺序发生,但不使用我认为的AAA语法( 源自2009年 ,可能已经发生变化, 编辑在这里看到可能有效的选项 ),但似乎有人开发了一种方法可能允许这里 I've never used that and can't verify it. 我从来没有用过,也无法验证它。

As for needing to know which method was called first so you can verify the exception you have a couple of choices: 至于需要知道哪个方法首先被调用,所以你可以验证异常,你有几个选择:

  • Have a different message in your exception and check that to determine which exception was raised. 在您的异常中有不同的消息并检查以确定引发了哪个异常。
  • Expect a call to daoA in addition to expecting the exception. 除了期待异常之外,还期待对daoA的调用。 If you don't get the call to daoA then the test fails as the exception must have been the first one. 如果你没有接到对daoA的调用,则测试失败,因为异常必须是第一个。

Often times you just need fake objects, not mocks. 通常你只需要假物品,而不是嘲笑。 Mock objects are meant to test component interaction, and often you can avoid this by querying the state of SUT directly. 模拟对象用于测试组件交互,通常可以通过直接查询SUT的状态来避免这种情况。 Most practical uses of mocks are to test interaction with some external system (DB, file system, webservice, etc.), and for other things you should be able to query system state directly. 模拟的最实际用途是测试与某些外部系统(数据库,文件系统,Web服务等)的交互,对于其他事项,您应该能够直接查询系统状态。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM