2015-03-09 3 views
0

В настоящее время у меня есть базовый класс обслуживания, который распространяется на все мои сервисы. Это то, что один из способов выглядеть следующим образом:Как модульный тестовый делегат был получен в методе базового класса?

protected internal virtual T PerformServiceOperationWithExceptionHandling<T>(Func<T> func) 
     { 
      try 
      { 
       return func.Invoke(); 
      } 

      ... 
     } 

В производных классах я называю метод, как это:

public AddGuestResponse AddGuest(AddGuestRequest addGuestRequest) 
    { 
     return PerformServiceOperationWithExceptionHandling(() => AddGuestLogic(addGuestRequest)); 
    } 

Я хочу проверить AddGuest и обеспечить «AddGuestLogic» в настоящее время передается в качестве параметр в базовом методе? Как достичь этого с помощью nSubstitute и nUnit. Я не думаю, что это возможно?

==================================================================================================================================== ==

Я в конечном итоге, используя следующий код:

[Test] 
    public void AddGuest_WhenCalled_PerformsAddGuestLogicWithExceptionHandling() 
    { 
     Func<AddGuestResponse> addGuestLogic = null; 
     _guestService.PerformServiceOperationWithExceptionHandling(Arg.Do<Func<AddGuestResponse>>(arg => addGuestLogic = arg)); 
     var addGuestRequest = new AddGuestRequest(); 
     _guestService.AddGuest(addGuestRequest); 
     _guestService.ClearReceivedCalls(); 

     addGuestLogic.Invoke(); 

     _guestService.Received().AddGuestLogic(addGuestRequest); 
    } 

_guestService создается в моем методе настройки следующим образом: Substitute.ForPartsOf();

ответ

2

Ответы второго Солнечного Миленова, но я бы сделал еще один шаг, посоветовав изменить свой дизайн. Я усвоил, что многие из этих головных болей при тестировании поведения базового класса исчезают, когда вы следуете принципу композиции над наследованием.

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

Вы должны проверить, что коллаборатор правильно вызывает функцию func в тестах соавтора.

В тестах Служб вы можете просто дразните соавтор возвращать результат в Func прямо прочь:

[Test] 
public void ServiceLogicIsExecuted() 
{ 
    var collaborator = Substitute.For<ICollaborator>(); 

    //Tell the test double to return the Func's result. You'd probably want to do this in the setup method. 
    collaborator.PerformServiceOperation(Arg.Any<Func<int>>()).Returns(x => ((Func<int>)x[0]).Invoke()); 

    var sut = new Service(collaborator); 

    var result = sut.CalculateSomething(); 

    Assert.That(result, Is.EqualTo(99)); 
} 

public class Service 
{ 
    private readonly ICollaborator _collaborator; 

    public Service(ICollaborator collaborator) 
    { 
     _collaborator = collaborator; 
    } 

    public int CalculateSomething() 
    { 
     return _collaborator.PerformServiceOperation(ExecuteLogic); 
    } 

    private static int ExecuteLogic() 
    { 
     return 99; 
    } 
} 

public interface ICollaborator 
{ 
    T PerformServiceOperation<T>(Func<T> func); 
} 
+0

Проблемы, которую я имею что я не могу проверить, чтобы увидеть, если мой метод базового класса получил правильную лямбду выражение. Даже если бы я изменил его в сторону композиции над наследованием (что-то, что я действительно рассматривал), у меня все еще есть одна и та же проблема, т. Е. Потому что два лямбда-выражения, хотя они одинаковы, будут указывать на два разных места памяти. –

+0

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

+0

Я добавил пример сервисного теста, в котором показано, как вы можете убедиться, что ваш двойник-сотрудник выполняет логику службы, которая передается ему как Func. Я не думаю, что Sunny предназначалось для дискредитации тестирования на основе взаимодействия. Его точка зрения заключается в том, что тестирование базового класса в изоляции малопригодно, потому что поведение базового класса всегда будет выполняться, взаимодействуя с логикой производного класса. – EagleBeak

1

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

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

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

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