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

时间:2011-10-04 06:48:38

标签: c# .net nunit rhino-mocks

我正在尝试为我的新项目设置测试并遇到一些困难。

我正在使用NUnit和Rhino Mocks。

我想测试的代码就是这个,

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);
}

我的测试代码如下

[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;
}

我需要传递一个documentDto,并说出isDirty set并测试它是否返回相同的对象。

所以我想使用Stub而不是模拟。

我需要找出如何设置期望,以便我可以测试代码上的逻辑。

1 个答案:

答案 0 :(得分:3)

您需要模拟或存根您不想测试的所有组件。根据经验,您应该只有一个模拟对象,其余应该是存根。模拟您想要验证交互的内容,并存储您想要为测试提供数据的内容。

你没有告诉我们你的_documentRepository是什么类型,所以很难确切地说明你在这里测试的是什么,但是为了测试这个方法你唯一可以做的事情,恕我直言,检查是否设置了IsDirty标志是检查_documentRepository和Context上的正确方法是否被调用。

为了做到这一点,我将创建一个模拟_documentRepository并模拟DbContext并设置在传入文档时调用_documentRepository.SaveOrUpdate(document)的期望。实际上再次查看需要在dto和文档之间进行转换的代码。目前,这是在一种方法中完成的。我将为此创建一个接口和一个类,并使该接口成为您正在测试的类的依赖项,以便您可以创建一个存根,该存根从documentDto返回一个已知文档。该类可以处理创建新文档或基于Dto中的id返回现有文档。否则你将不得不知道返回什么类型的文件。

类似的东西:

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());

然后为存储库创建一个模拟

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>);

这会测试您在设置脏标志时是否正确地与存储库对象进行交互。它不应该测试文档是否正确保存或者在调用SaveOrUpdate时返回正确的文档,因为这应该在存储库的测试中进行测试,而不是在这里。

'但等等!'我听到你哭了,'你刚开始说,应该只有一个模拟器,这里我们有2个!'。这是真的,我认为这显示了您当前设计的错误。

我不认为你不应该从documentRepository中公开DBContext。您似乎这样做是为了使用交易。

如果您的存储库需要知道事务,那么存储库中的方法允许控制事务(或隐藏事务存储库对象内部完全存在的事实)。这些方法可能只是委托给内部DbContext但它意味着唯一的mock需要是文档存储库对象本身,而不是DbContext