Модульное тестирование и реализация Fake Repository с каскадными операциями CRUD - PullRequest
2 голосов
/ 21 мая 2010

У меня проблемы с написанием интеграционных тестов, использующих поддельный репозиторий,

Например: предположим, у меня есть объект в классе, который объединяет студентов ...

var classroom = new Classroom();
classroom.Students.Add(new Student("Adam"));

_fakeRepository.Save(classroom);

_fakeRepostiory.GetAll<Student>().Where((student) => student.Name == "Adam")); 
// This query will return null...

При использовании моей реальной реализации для репозитория (на основе NHibernate) вышеуказанный код работает (поскольку операция сохранения будет каскадно добавляться к студенту, добавленному в предыдущей строке),

Вам известна какая-либо реализация поддельного репозитория, поддерживающая это поведение? Идеи о том, как реализовать это самостоятельно?

Или у вас есть другие предложения, которые могут помочь мне избежать этой проблемы?

Спасибо заранее, Эрик.

Ответы [ 3 ]

2 голосов
/ 21 мая 2010

Если вы пишете «интеграционный тест», как указано в тексте вашего вопроса, вы бы не использовали фальшивую реализацию - используйте реальную вещь.

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

Если вы пишете модульный тест, описывающий способность NHibernate выполнять каскадные операции, они уже написаны и ничего не доказывают в классе Classroom.

Редактировать в ответ на комментарий:

Модульные тесты используются для тестирования отдельных «модулей» функциональности, независимо от любых других классов или служб - в этом случае вы используете подделки для этих других классов, чтобы убедиться, что они выполняют именно то, что нужно этому классу. Интеграционные тесты используются для проверки взаимодействия между несколькими классами и / или подсистемами (такими как доступ к базе данных, ORM и т. Д.). В этом случае кажется, что вы хотите протестировать каскадное сохранение / обновление, но в этом и заключается ответственность NHibernate, не так ли?

Но, скажем, у вас есть класс, который сохраняет classroom с использованием IRepository<Classroom>, и он оборачивает это действие в блок try…catch, и вы хотите выполнить модульный тест, когда IRepository<Classroom> выдает RepositoryWriteFailureException , свойство подсчета ошибок, ErrorCount увеличивается. Здесь вам do нужна фальшивая реализация вашего репозитория, и именно здесь вступает в игру фальшивый фреймворк, такой как RhinoMocks, nMock, Moq или TypeMock Isolator - они могут сгенерировать фальшивку для вас, используя интерфейс , абстрактный класс или класс, чьи открытые методы и свойства были объявлены virtual.

Я мог бы написать тело теста следующим образом (трактовать это как псевдокод):

// set up the context (arrange)

// create the fake repository
var fake_repository = MockRepository.GenerateStub<IRepository<Classroom>>();

// create the classroom, injecting the fake repository
dim classroom as new Classroom(fake_repository);

// now tell the fake how to behave
fake_repository.Stub(repo => repo.Save(classroom))
    .WhenCalled(throw new RepositoryWriteFailureException());

// do what you're testing (act)
classroom.Save(); 


// assert the expected behaviour (assert)

// verify that the fake_repository was told to Save(classroom)
Assert.IsTrue(fake_repository.WasToldTo(repo => repo.Save(classroom)).Times(1);

// verify that the error count property was incremented
Assert.IsTrue(classroom.ErrorCount == 1);

Обратите внимание, как мы проверили, как класс Classroom, или что вы тестируете, ведет себя без необходимости реализовывать репозиторий.

1 голос
/ 21 мая 2010

Поскольку это интеграционный тест, я бы порекомендовал вам использовать реальный репозиторий, а не просто фальшивый.

Хорошим решением было бы создать отдельную базу данных для целей тестирования и установить для свойства hbm2ddl.auto NHibernate значение create в файле конфигурации тестового проекта, чтобы каждый раз при этом заново создавалась база данных, так что об этом надо беспокоиться.

Я использую именно это для целей тестирования. Я использую автоматический картограф FluentNHibernate с пользовательскими соглашениями. Вы также можете использовать SQLite, если вы хотите использовать для тестирования что-то более легкое, чем SQL Server.
(Я тестирую свой репозиторий таким образом, используя SQL Server.)

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

0 голосов
/ 21 мая 2010

+ 1 за то, что он не называется «интеграционным тестом», если тест не использует реальную вещь (т.е. не тестирует интеграцию с СУБД).

Если вы хотите использовать каскадирование и все остальные преимущества NHibernate и скорость «модульного теста», я считаю использование базы данных в памяти (SQLite) чрезвычайно полезным.

...