简体   繁体   English

使用RhinoMocks进行单元测试和模拟

[英]Unit Testing and Mocking using RhinoMocks

I am trying to setup tests for my new projects and come across some difficulties. 我正在尝试为新项目设置测试并遇到一些困难。

I am using NUnit and Rhino Mocks. 我正在使用NUnit和Rhino Mocks。

The Code that I am trying to test is this, 我要测试的代码是这样的,

public DocumentDto SaveDocument(DocumentDto documentDto)
{
    Document document = null;
    using (_documentRepository.DbContext.BeginTransaction())
    {
        try
        {
            if (documentDto.IsDirty)
            {
                if (documentDto.Id == 0)
                {
                    document = CreateNewDocument(documentDto);
                }
                else if (documentDto.Id > 0)
                {
                    document = ChangeExistingDocument(documentDto);
                }

                document = _documentRepository.SaveOrUpdate(document);
                _documentRepository.DbContext.CommitChanges();
            }
        }            
        catch
        {
            _documentRepository.DbContext.RollbackTransaction();
            throw;
        }
    }
    return MapperFactory.GetDocumentDto(document);
}

And my testing code is as follows 我的测试代码如下

[Test]
public void SaveDocumentsWithNewDocumentWillReturnTheSame()
{
    //Arrange

    IDocumentService documentService = new DocumentService(_ducumentMockRepository,
            _identityOfSealMockRepository, _customsOfficeOfTransitMockRepository,
            _accountMockRepository, _documentGuaranteeMockRepository,
            _guaranteeMockRepository, _goodsPositionMockRepository);
    var documentDto = new NctsDepartureNoDto();
    documentDto.IsDirty = true;
    documentDto.Id = 0;
    //Act
    var retDocumentDto = documentService.SaveDocument(documentDto);

    //Assert
    Assert.AreEqual(documentDto, documentDto);
}

private static IDbContext CreateMockDbContext()
{
    var dbContext = MockRepository.GenerateMock<IDbContext>();

    // setup expectations for DbContext mock
    //dbContextMock.Expect(...)
    // bind mock of the DbContext to property of repository.DbContext
    _ducumentMockRepository.Expect(mock => mock.DbContext).Return(dbContext).Repeat.Any();


    return dbContext;
}

I need to pass in a documentDto with say isDirty set and test if it returns the same object. 我需要传入带有isDirty的documentDto并测试它是否返回相同的对象。

So I was thinking to use a Stub instead of a mock. 所以我在考虑使用存根而不是模拟。

I need to to find out how to set expectations so I can test the logic on the code. 我需要找出如何设定期望值,以便可以测试代码上的逻辑。

you need to mock or stub all of the components which you do not want to test. 您需要模拟或存根您不想测试的所有组件。 You should, as a rule of thumb only have a maximum of single mock object the rest should be stubs. 根据经验,您应该最多只能有一个模拟对象,其余的应该是存根。 Mock the things you want to verify interaction with and stub the things which you just want to provide data for your test. 模拟您要验证与之交互的内容,并对您只想为测试提供数据的内容进行存根。

you don't tell us what type your _documentRepository is so its hard to tell exactly what you are testing here, but to test this method the only thing you can do, IMHO, is check that if the IsDirty flag is set is check that the correct methods on the _documentRepository and the Context are called. 您没有告诉我们_documentRepository是什么类型,因此很难在此处准确地说明您要测试的内容,但是要测试此方法,您唯一可以做的事,恕我直言,请检查是否已设置IsDirty标志,调用了_documentRepository和Context上的正确方法。

To do this I would create a mock _documentRepository and mock DbContext and set expectations that _documentRepository.SaveOrUpdate(document) is called with the document passed in. Actually looking again at the code you need to convert between the dto and the document. 为此,我将创建一个模拟_documentRepository和模拟DbContext并设置期望_documentRepository.SaveOrUpdate(document)与传入的文档一起调用。实际上,再次查看您需要在dto和文档之间进行转换的代码。 Currently this is being done in a method. 当前,这是通过一种方法来完成的。 I would create a interface and a class for this and make that interface a dependency of the class you are testing so that you can create a stub which returns a known document from the documentDto. 我将为此创建一个接口和一个类,并使该接口成为您正在测试的类的依赖项,以便您可以创建一个存根,该存根从documentDto返回已知的文档。 This class could handle creating a new document or returning an existing one based on the id in the Dto. 此类可以根据Dto中的ID处理创建新文档或返回现有文档的情况。 otherwise you'll have to know what type of document is returned. 否则,您将必须知道返回的文档类型。

something like: 就像是:

var documentDto = new NctsDepartureNoDto();
documentDto.IsDirty = true;
documentDto.Id = 0;

IDbContext context = MockRepository.GenerateMock<IDbRepository>();  
context.Expect(x=>x.BeginTransaction()).Return(MockRepository.GenerateStub<ITransaction>());
context.Expect(x=>x.CommitChanges());

then create a mock for the repository 然后为存储库创建一个模拟

IDocumentRepository repo = MockRepository.GenerateMock<IDocumentRepository>();
repo.Expect(x=>x.DbContext).Return(context).Repeat().Any();
repo.Expect(x=>x.SaveOrUpdate(Arg<Document>.Is.Any())).Return(MockRepository.GenerateStub<Document>);

This tests that you interact with the repository object correctly when the dirty flag is set. 当设置了脏标志时,这测试您是否与存储库对象正确交互。 It shouldn't test that the document is saved correctly or that the correct document is returned when SaveOrUpdate is called, as this should be tested in the tests for the repository, not here. 它不应测试在调用SaveOrUpdate时是否正确保存了文档或返回了正确的文档,因为不应在存储库的测试中测试该文档。

'But wait!' '可是等等!' I hear you cry, 'you said at the beginning that there should only be a single mock, and here we have 2!'. 我听到您在哭,“您在一开始就说只能有一个模拟,这里有2个!”。 That's true, and I think that this shows a fault in your current design. 是的,我认为这表明您当前的设计有缺陷。

You should not, I don't think, be exposing the DBContext from your documentRepository. 我不认为,您不应从documentRepository中公开DBContext。 You seem to be doing so in order to use the transactions. 您似乎这样做是为了使用事务。

If your repository needs to be aware of the transactions then have methods on the repository that allow the transactions to be controlled (or hide the fact that the transactions exist inside the repository object completely). 如果您的存储库需要了解事务,则在存储库上有一些方法可以控制交易(或隐藏交易完全存在于存储库对象中的事实)。 These methods might just delegate to the internal DbContext but it would then mean that the only mock would need to be the document repository object itself, and not the DbContext 这些方法可能只是委托给内部DbContext,但这意味着唯一的模拟应该是文档存储库对象本身,而不是DbContext

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

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