2013-06-27 7 views
2

Итак, я пытаюсь написать несколько тестовых примеров для моего уровня бизнес-логики. Я уже высмеял свой уровень доступа к данным (который возвращает объекты NHibernate IQueryOver). Я создал класс MockQueryOver, который реализует интерфейс IQueryOver, потому что я цепляю функции на уровне бизнес-логики, поэтому создание заштрихованного IQueryOver для меня не имеет смысла.Mock NHibernate Объект IQueryOverOrderBuilder

В любом случае, все работает, но проблема, с которой я сталкиваюсь, - это когда я пытаюсь сделать OrderBy() на QueryOver. В моем MockQueryOver классе я реализовать OrderBy() метод, как это прямо сейчас:

public IQueryOverOrderBuilder<TRoot, TSubType> OrderBy(Expression<Func<TSubType, object>> path) 
{ 
    var func = path.Compile(); 
    IList<TSubType> result = m_data.OrderBy(func).ToList(); 
    var mockRepo = new MockRepository(); 
    var queryOver = new MockQueryOver<TRoot, TSubType>(m_data); 

    IQueryOverOrderBuilder<TRoot, TSubType> mockOrderBuilder = mockRepo.StrictMock<IQueryOverOrderBuilder<TRoot, TSubType>>(queryOver, path); 
    mockOrderBuilder.Stub(x => x.Desc).Return(queryOver); 
    mockOrderBuilder.Stub(x => x.Asc).Return(queryOver); 

    return mockOrderBuilder; 
} 

Проблема заключается в том, что RhinoMocks бросает исключение на любом из методов заглушки. Это исключение:

System.NullReferenceException : Object reference not set to an instance of an object. 
at NHibernate.Criterion.Lambda.QueryOverOrderBuilderBase`3.AddOrder(Func`2 orderStringDelegate, Func`2 orderDelegate) 
at NHibernate.Criterion.Lambda.QueryOverOrderBuilderBase`3.get_Desc() 
at NHibernate.Criterion.QueryOverBuilderExtensions.Desc(IQueryOverOrderBuilder`2 builder) 
at BLL.Tests.Mock_Objects.MockQueryOver`2.<OrderBy>b__7(IQueryOverOrderBuilder`2 x) in MockQueryOverSubType.cs: line 239 

Я новичок в NHibernate и RhinoMocks, так что я не уверен, что он делает за кулисами, но кажется, что даже если я создаю издеваться над интерфейсом, он по-прежнему вызывает конкретные методы расширения, когда я пытаюсь заглушить метод.

Может кто-то прояснить это или помочь мне с этой проблемой? Кроме того, поскольку я только начинаю писать эти тестовые примеры, я не возражаю переключать насмешливые фреймворки, если он свободен в использовании.

Большое спасибо!

ответ

3

У вас есть IQueryOverOrderBuilder - это интерфейс? Кажется, a confusingly-named class that implements QueryOverOrderBuilderBase. Я не совсем уверен, что такое поведение в этой ситуации, но я думаю, что ваш StrictMock из IQueryOverOrderBuilder действительно вызывает этот базовый класс, который, вероятно, не настроен, и бросает исключение, которое вы видите.

Я думаю, что, возможно, вам может понадобиться добавить еще один слой абстракции между вашей бизнес-логикой и NHibernate, с классами, которые вы можете надежно высмеивать. Я не думаю есть способ издеваться над конкретным классом, как IQueryOverOrderBuilder с RhinoMocks (но я рад, что исправлен, если есть :).

Чтобы создать еще один уровень абстракции, проанализируйте операции в вашей бизнес-логике, которые в настоящее время взаимодействуют с NHibernate, и определите новый интерфейс функций для инкапсуляции этих операций (скажем, IRepository). Код, который добавляет что-то в базу данных через NHibernate, может стать функцией на интерфейсе с именем AddItem. Переместите код, который взаимодействует с NHibernate за этим интерфейсом, в новые функции нового класса (нет причин, по которым он должен быть одним классом - вы могли бы группировать логически связанный код в отдельные классы с отдельными интерфейсами). Новый интерфейс может ссылаться на некоторые классы и интерфейсы NHibernate, которые могут быть легко созданы или издеваться соответственно (в идеале интерфейс не будет ссылаться на NHibernate вообще, но вы делаете это для тестирования, а не для полного развязывания кода от NHibernate, так что все хорошо). Как только вы это сделаете, ваша бизнес-логика может быть подвергнута единичному тестированию против макета (или mocks) нового интерфейса, а класс или классы, реализующие этот интерфейс, могут быть протестированы по интеграции с реальной базой данных. Это, бесплатно, Adapter pattern. Не видя точно, что делает ваша бизнес-логика, сложно комментировать дальнейший дизайн. Надеюсь, это полезно.

Наконец, если вы создаете свой собственный MockRepository, я думаю, вам нужно позвонить Replay() на издевается вы создаете (или ReplayAll() на MockRepository) после того, как вы их окурок.Вам не нужно это делать, если вы создаете свои mocks из статических методов на MockRepository. Кажется, не связано с вашей текущей проблемой (хотя, попробуйте позвонить ему после ваших звонков Stub и посмотреть, не имеет ли это никакого значения), но я думал, что упомянул об этом в любом случае.

+0

Да, вы правы в том, что это конкретный класс, называемый интерфейсом. Не могли бы вы дать мне базовый пример того, как я могу создать промежуточный слой? Я не совсем уверен, что я могу сделать. –

+0

Я добавил дополнительную информацию о создании слоя абстракции между вашей бизнес-логикой и NHibernate. Надеюсь, это понятно и полезно. Пожалуйста, спросите, нет ли чего-то. –