Модульное тестирование и Mocking с использованием RhinoMocks - PullRequest
1 голос
/ 04 октября 2011

Я пытаюсь настроить тесты для моих новых проектов и сталкиваюсь с некоторыми трудностями.

Я использую 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 и проверить, возвращает ли он тот же объект.

Так что я думал использовать заглушку вместо насмешки.

Мне нужно выяснить, как установить ожидания, чтобы я мог проверить логику в коде.

1 Ответ

3 голосов
/ 05 октября 2011

вам нужно смоделировать или заглушить все компоненты, которые вы не хотите тестировать.Вы, как правило, должны иметь максимум один макет объекта, остальные должны быть заглушками.Подшучивайте над вещами, с которыми вы хотите проверить взаимодействие, и окуривайте вещи, которые вы просто хотите предоставить для своего теста.

вы не говорите нам, какого типа ваш _documentRepository, поэтому трудно точно сказать, кто вытестирование здесь, но для тестирования этого метода единственное, что вы можете сделать, IMHO, это проверить, что если установлен флаг IsDirty, это проверить, что вызываются правильные методы в _documentRepository и Context.

Для этогоЯ бы создал макет _documentRepository и макет DbContext и установил ожидания, что _documentRepository.SaveOrUpdate(document) вызывается с переданным документом. На самом деле, снова смотря на код, который вам нужно конвертировать между dto и документом.В настоящее время это делается методом.Я бы создал интерфейс и класс для этого и сделал бы этот интерфейс зависимостью от класса, который вы тестируете, чтобы вы могли создать заглушку, которая возвращает известный документ из documentDto.Этот класс может обрабатывать создание нового документа или возврат существующего на основе идентификатора в Dto.в противном случае вам нужно будет знать, какой тип документа возвращается.

что-то вроде:

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!».Это правда, и я думаю, что это указывает на ошибку в вашем текущем дизайне.

Вы не должны, я не думаю, выставлять DBContext из вашего documentRepository.Вы, кажется, делаете это для того, чтобы использовать транзакции.

Если вашему хранилищу нужно знать о транзакциях, то в хранилище должны быть методы, позволяющие контролировать транзакции (или скрыть тот факт, что транзакции существуют внутри объекта хранилища полностью).Эти методы могут просто делегировать внутреннему DbContext, но тогда это будет означать, что единственным макетом должен быть сам объект хранилища документов, а не DbContext

...