Тестирование и издевательство над частными / защищенными методами. Многие посты, но все еще не могут заставить один пример работать - PullRequest
12 голосов
/ 05 июня 2010

Я видел много постов и вопросов о «издевательстве над личным методом», но до сих пор не могу заставить его работать и не нашел реального ответа. Давайте забудем запах кода, и вы не должны делать это и т.д. ....

Из того, что я понимаю, я сделал следующее:

1) Создан класс библиотеки "MyMoqSamples"

2) Добавлены ссылки на Moq и NUnit

3) Отредактировал файл AssemblyInfo и добавил [сборка: InternalsVisibleTo ("DynamicProxyGenAssembly2")] [сборка: InternalsVisibleTo ("MyMoqSamples")]

4) Теперь нужно протестировать закрытый метод. Так как это закрытый метод, он не является частью интерфейса.

5) добавили следующий код

[TestFixture]
public class Can_test_my_private_method
{
    [Test]
    public void Should_be_able_to_test_my_private_method()
    {
        // TODO how do I test my DoSomthing method?
    }
}

public class CustomerInfo
{
    public string Name { get; set; }
    public string Surname { get; set; }
}

public interface ICustomerService
{
    List<CustomerInfo> GetCustomers();
}

public class CustomerService : ICustomerService
{
    public List<CustomerInfo> GetCustomers()
    {
        return new List<CustomerInfo> { new CustomerInfo { Surname = "Bloggs", Name = "Jo" } };
    }

    protected virtual void DoSomething()
    {
    }
}

Не могли бы вы привести пример того, как вы будете тестировать мой приватный метод? Большое спасибо

Ответы [ 2 ]

14 голосов
/ 06 июня 2010

Шаги, которые вы описываете, настраивают Moq для тестирования внутренних классов и членов, поэтому на самом деле не имеют ничего общего с тестированием защищенного или частного метода

Тестирование приватных методов - это неприятный запах, вам действительно нужно протестировать только публичный API. Если вы чувствуете, что метод действительно важен и нуждается в тестировании в отдельности, возможно, он заслуживает того, чтобы быть в своем собственном классе, где его можно потом протестировать самостоятельно?

Если ваше сердце настроено на тестирование защищенного метода, описанного выше, вы можете свернуть свой собственный макет в своей тестовой сборке:

public class CustomerServiceMock : CustomerService {
    public void DoSomethingTester() {
         // Set up state or whatever you need
         DoSomething();
    }

}

[TestMethod]
public void DoSomething_WhenCalled_DoesSomething() {
    CustomerServiceMock serviceMock = new CustomerServiceMock(...);
    serviceMock.DoSomethingTester();
 }

Если бы это было личное, вы, вероятно, могли бы сделать что-то хитрое с отражением, но идти по этому пути - путь к испытанию ада.


Обновление

Пока вы приводите пример кода в своем вопросе, я не вижу, как вы хотите «протестировать» защищенный метод, поэтому я придумаю что-то придуманное ...

Допустим, ваша служба поддержки выглядит так: -

 public CustomerService : ICustomerService {

      private readonly ICustomerRepository _repository;

      public CustomerService(ICustomerRepository repository) {
           _repository = repository;
      } 

      public void MakeCustomerPreferred(Customer preferred) {
           MakePreferred(customer);
           _repository.Save(customer);
      }

      protected virtual void MakePreferred(Customer customer) {
          // Or more than likely some grungy logic
          customer.IsPreferred = true;
      }
 }

Если вы хотите проверить защищенный метод, вы можете просто сделать что-то вроде: -

[TestClass]
public class CustomerServiceTests {

     CustomerServiceTester customerService;
     Mock<ICustomerRepository> customerRepositoryMock;

     [TestInitialize]
     public void Setup() {
          customerRepoMock = new Mock<ICustomerRepository>();
          customerService = new CustomerServiceTester(customerRepoMock.Object);
     }


     public class CustomerServiceTester : CustomerService {    
          public void MakePreferredTest(Customer customer) {
              MakePreferred(customer);
          }

          // You could also add in test specific instrumentation
          // by overriding MakePreferred here like so...

          protected override void MakePreferred(Customer customer) {
              CustomerArgument = customer;
              WasCalled = true;
              base.MakePreferred(customer);
          }

          public Customer CustomerArgument { get; set; }
          public bool WasCalled { get; set; }
     }

     [TestMethod]
     public void MakePreferred_WithValidCustomer_MakesCustomerPreferred() {
         Customer customer = new Customer();
         customerService.MakePreferredTest(customer);
         Assert.AreEqual(true, customer.IsPreferred);
     }

     // Rest of your tests
}

Имя этого "шаблона" - специфичный для Test подкласс (основанный на терминологии тестовых шаблонов xUnit) для получения дополнительной информации, которую вы можете увидеть здесь: -

http://xunitpatterns.com/Test-Specific%20Subclass.html

Судя по вашим комментариям и предыдущему вопросу, вам кажется, что вам поручено внедрить модульные тесты для какого-то устаревшего кода (или вы приняли решение самостоятельно). В этом случае библия всех вещей унаследованного кода - это книга Майкла Фезерса. Он охватывает такие методы, как рефакторинг и методы, позволяющие разбить «непроверяемые» классы и методы на нечто более управляемое, и я настоятельно рекомендую это.

1 голос
/ 06 июня 2010

Похоже, что две части вашего вопроса.

  1. Как мне издеваться над защищенным методом:

    http://blogs.clariusconsulting.net/kzu/mocking-protected-members-with-moq/

  2. как мне вызвать вызов этого защищенного / личного поведения в моем тесте

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

Я предлагаю вам подумать о том, что вы пытаетесь продемонстрировать / доказать в своем тесте. Если вы пишете сложный тест, значит, вы делаете это неправильно. Возможно, то, что вы хотите сделать, можно разбить на независимые тесты? Возможно, вы пишете интеграционный тест, а не юнит-тест? Но есть много статей о плохих тестах, и больше будет иметь смысл для вас, когда вы научитесь писать хорошие тесты. Два из моих любимых http://www.codethinked.com/post/2009/06/30/What-is-Unit-Testing.aspx и http://www.codethinked.com/post/2009/11/05/Ite28099s-Okay-To-Write-Unit-Tests.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...