2015-08-28 2 views
1

Я работаю над написанием некоторых модульных тестов с Rhino Mocks для приложения WPF, написанного на C#, который использует Unity для инъекции зависимостей и использует MVVM-айтиктура. Я не очень разбираюсь в модульном тестировании с Rhino Mocks, поэтому я не уверен, какие лучшие практики еще нет.Rhino Mocks - ожидать/заглушить не виртуальный метод из внешней зависимости

В модели представления я собираюсь писать модульные тесты, есть класс ввода данных с зависимостями, мы будем называть его DataAccess, то есть из внешней сборки, которую я не контролирую. Только один экземпляр зарегистрирован в контейнере Unity, потому что DataAccess имеет кэш, и желательно разделить этот экземпляр по всему приложению через контейнер Unity, чтобы повысить производительность. Теперь мне нужно издеваться над DataAccess в моем модульном тесте, потому что я не контролирую данные в базе данных. Я хочу заглушить или ожидать, что метод Retrieve вернет определенное значение, но DataAccess не реализует интерфейс, а метод, который мне нужен для заглушки, не является виртуальным. Из того, что я читал онлайн, Rhino Mocks не может переопределить не виртуальный метод, и единственным другим вариантом является издевательствование интерфейса с методами, которые вы хотите переопределить. Ни один из этих параметров не подходит для этого случая, потому что у меня нет кода DataAccess. Я слышал, что TypeMock имеет возможность переопределять не виртуальные методы, но убедить мою компанию переключиться на платную насмешливую библиотеку, вероятно, не произойдет, поэтому я застрял с Rhino Mocks. Так есть способ издеваться над этим классом и переопределить этот метод Rhino Mocks?

public class DataAccess //in an external assembly 
{ 
    public TEntity Retrieve(TKey key); 
} 

public class ViewModel //in the client project 
{ 
    [Dependency] 
    public DataAccess DataAccess { get; set; } 
} 

я придумал возможное решение, но он не использует издевается, и я хотел бы использовать издевается, потому что есть много мест, где мы имеем такую ​​ситуацию. Моя идея - создать класс-оболочку (поддельный) для DataAccess, который имеет те же методы и свойства, что и DataAccess, за исключением того, что все важные методы/свойства отмечены как виртуальные, и я положу этот класс в свой тестовый проект. Затем в инициализаторе модульного теста я зарегистрирую сопоставление типов из DataAccess в класс оболочки в контейнере Unity, чтобы виртуальная машина, созданная в моем модульном тесте, вместо этого получала экземпляр класса-оболочки. Вы видите какие-то недостатки в этом направлении, кроме создания кучи классов-оболочек?

public class DataAccessFake : DataAccess //in the test project 
{ 
    public new virtual TEntity Retrieve(TKey key) //hides the DataAccess Retrieve with a virtual one 
    { 
     return base.Retrieve(key); 
    } 
} 
+0

Действительно ли это работает? Объекты, которые зависят от DataAccess, по-прежнему будут вызывать DataAccess.Retrieve, а не DataAccessFake.Retrieve, которые являются двумя совершенно разными способами. –

+0

Ключевое слово 'new' указывает, что метод скрывает свой унаследованный элемент. Так что да, он должен назвать поддельный метод. – StarChar

+0

Вы проверили это? –

ответ

0

Вот код, который я испытал, чтобы показать, что предлагаемый подход не будет работать:

class Program 
{ 
    static void Main(string[] args) 
    { 
     ViewModel vm = new ViewModel() 
     { 
      DataAccess = new DataAccessFake() 
     }; 

     string result = vm.Test("test"); //this returns "test_original" 
    } 
} 

public class ViewModel 
{ 
    public DataAccess DataAccess { get; set; } 

    public string Test(string key) 
    { 
     return DataAccess.Retrieve(key); 
    } 
} 

public class DataAccess 
{ 
    public string Retrieve(string key) 
    { 
     return key + "_original"; 
    } 
} 

public class DataAccessFake : DataAccess 
{ 
    public new virtual string Retrieve(string key) 
    { 
     return key + "_fake"; 
    } 
} 

Если запустить этот код, выход методы испытаний будет «test_original», который показывает, что метод DataAccessFake.Retrieve никогда не вызывался. Вы также можете установить контрольную точку в таком методе для проверки.

Поскольку ViewModel зависит от DataAccess, он всегда будет вызывать DataAccess.Retrieve, который является совершенно другим методом, чем DataAccessFake.Retrieve.

Конечно, поведение было бы совсем иным, если DataAccessFake.Retrieve был переопределенным методом DataAccess.Retrieve.

+0

А, я вижу. Я только проверял, можно ли вызвать скрытый метод, если он был объявлен как DataAccessFake. Если он объявлен как DataAccess, но установлен в экземпляр DataAccessFake, он не вызывает поддельный метод. Поэтому я думаю, что моя идея не работает, и для этого мне пришлось бы заменить зависимость DataAccess с DataAccessFake, которая на самом деле не является хорошим решением. Спасибо хоть. – StarChar

Смежные вопросы