我正在尝试为我的新项目设置测试并遇到一些困难。
我正在使用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而不是模拟。
我需要找出如何设置期望,以便我可以测试代码上的逻辑。
答案 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