2016-08-04 2 views
2

Я работаю, чтобы получить некоторые тесты на устаревшем коде (здесь это означает «код без модульных тестов»). Иногда соблюдаются хорошие практики, но часто нет. Однако я не смог понять, что нужно делать в этом случае.Moq: Издевательство над классом с множественным наследованием

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

Метод, который я хочу проверить, это FilterController.SomeMethod (whatever_params). FilterController наследуется от BaseController. И я добавил в простой интерфейс IFilterController, чтобы сделать так, чтобы FilterController наследовался как от BaseController, так и от IFilterController. Единственный метод, который у меня есть в интерфейсе, - это метод, который я хочу проверить («SomeMethod»).

В настоящее время конструктор FilterController - это то место, где я сталкиваюсь с проблемами при переходе в BaseController.

public interface IFilterController { ActionResult SomeMethod(string s, bool b) } 

public class FilterController : BaseController, IFilterController { 
    public FilterController(IFoo1 foo1, IFoo2 foo2, IFoo3 foo3, IFoo4 foo4) 
     : base(typeof(FilterController), foo1, foo2, foo3, foo4) {} 
    public ActionResult SomeMethod(string s, bool b) { // implementation } 


// and the BaseController... 
public BaseController(Type type, IFoo1 foo1, IFoo2 foo2, IFoo3 foo3, IFoo4 foo4) 
    { 
     // call that blows up due to not knowing how to mock the call inside here 
     _somePrivateProperty = _someOtherInterface.someCallThatIsntMocked(some_params) 
     // other stuff 
    } 

код, который я в настоящее время за попытку установки тест устройства (MSTest с FluentAssertions и Moq):

private FilterController filterController; 
    private Mock<IFilterController> filterControllerMock; 
    private Mock<IFoo1> foo1mock; 
    private Mock<IFoo2> foo2mock; 
    private Mock<IFoo3> foo3mock; 
    private Mock<IFoo4> foo4mock; 

    [ClassInitialize] 
    public static void ClassInit(TestContext context) {} 

    [TestInitialize] 
    public void Initialize() 
    { 
     filterControllerMock = new Mock<IFilterController>(); 
     foo1mock = new Mock<IFoo1>(); 
     foo2mock = new Mock<IFoo2>(); 
     foo3mock = new Mock<IFoo3>(); 
     foo4mock = new Mock<IFoo4>(); 

     // here is where the test bombs out with exceptions due to the base class making calls to stuff not mocked 
     filterController = new FilterController(foo1mock.Object, foo2mock.Object, foo3mock.Object, foo4mock.Object); 
    } 

    [TestCleanup] 
    public void Cleanup(){} 

    [ExpectedException(typeof(CustomException))] 
    [TestMethod] 
    public void SomeMethod_ForcedErrorScenario_CatchesCustomException() 
    { 
     // Arrange 
     filterControllerMock 
      .Setup(x => x.SomeMethod(It.IsAny<string>(), It.IsAny<bool>())) 
      .Returns(new CustomException()); 

     // Act 
     var result = filterController.SomeMethod("Foobar", false);   
    } 

В этом случае есть Try Поймайте блок, который я убедившись, что обрабатывается правильно, когда он попадает в блок catch для подтверждения ошибки. Меня не волнует, как исключение выбрасывается для цели теста, просто он пойман и делает то, что я ожидаю после него. Однако, как я уже сказал, я не могу пройти мимо попытки издеваться над самим конструктором FilterController, чтобы сделать вызов его конкретному методу из-за того, что он наследует BaseController.

- EDIT: Решена проблема. В BaseController объект _someOtherInterface был создан на основе одного из интерфейсов, переданных в конструкторе. В моем методе MSTest Initialize мне просто нужно было сделать так, чтобы интерфейс не был нулевой ссылкой, а затем переопределял метод, к которому он вызвал с помощью Setup (x => x.otherMethod()). Возвращает (_someOtherInterface.Object).

+1

Как реальное приложение создает экземпляр '_someOtherInterface'? Он не вводится. Похоже, вам нужно будет реорганизовать это, чтобы заставить его работать. – Jonesopolis

+0

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

+0

рад слышать, что вы добиваетесь прогресса – Jonesopolis

ответ

1

Узнал мой вопрос ... в BaseController

// I didn't realize the _someOtherInterface was instantiated based off an interface passed in 
_someOtherInterface = _IFoo1.AMethodNotMocked(); 
// many lines later... 
_somePrivateProperty = _someOtherInterface.SomeMockedMethod() 

Чтобы решить эту проблему, я должен был затем сделать так, в методе [TestInitialize] Присвоить прежде чем он пытался создать filterController = новый FilterController (interfacemock .Object), мне пришлось переопределить _IFoo1.AMethodNotMocked. Как так:

IFoo1.Setup(s => AMethodNotMocked()).Returns(new Foobar()) 

Это сделало так, когда испытание под FilterController, интерфейс IFoo1 была заселена так пустая ссылка ошибка не была брошена.

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