2010-06-05 6 views
11

He visto muchas publicaciones y preguntas sobre "Burlarse de un método privado", pero todavía no puedo hacer que funcione y no encontré una respuesta real. olvidemos el olor de código y que no debería hacerlo, etc ....Prueba y burla de métodos privados/protegidos. Muchas publicaciones pero todavía no pueden hacer que un ejemplo funcione

Por lo que entiendo que he hecho las siguientes:

1) Creado MyMoqSamples "" una biblioteca de clases

2) Se ha añadido una referencia a Moq y NUnit

3) Editado el archivo AssemblyInfo y ha añadido [assembly: InternalsVisibleTo ("DynamicProxyGenAssembly2")] [assembly: InternalsVisibleTo ("")] MyMoqSamples

4) Ahora es necesario probar un método privado. Dado que es un método privado, no forma parte de una interfaz.

5) que se añade el siguiente código

[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() 
    { 
    } 
} 

¿Me podría dar un ejemplo de cómo se podría probar mi método privado? Muchas gracias

Respuesta

14

Los pasos que describes establecer Moq para poner a prueba las clases internas y miembros también lo han hecho en realidad nada que ver con la evaluación de un método protegido o privado

métodos privados de análisis es un poco de olor, realmente deberías probar solo la API pública. Si considera que el método es realmente importante y necesita ser probado de manera aislada, ¿quizás merece ser parte de su propia clase, donde puede ser probado por sí mismo?

Si su corazón está puesto en probar el método protegido de arriba se puede rodar su propia Mock en su conjunto de prueba:

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(); 
} 

Si era privado que probablemente podría hacer algo raro con la reflexión, pero ir por ese camino es la forma de probar el infierno.


actualización

Mientras que usted ha dado ejemplo de código en su pregunta que realmente no veo cómo desea "probar" el método protegido así que voy a llegar a algo artificial. ..

digamos que su servicio al cliente es el siguiente: -

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; 
     } 
} 

Si quería probar el método protegido que pueda ju st hacer algo como: -

[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 
} 

El nombre de este "patrón" es prueba subclase específica (basado en xUnit terminología patrones de prueba) para obtener más información es posible que desee ver aquí: -

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

Según sus comentarios y preguntas anteriores, parece que se le ha encomendado la tarea de implementar pruebas unitarias sobre algún código heredado (o tomó la decisión usted mismo).En cuyo caso, el código heredado de la Biblia de todas las cosas es el libro de Michael Feathers. Cubre técnicas como esta, así como refactorizaciones y técnicas para tratar la descomposición de clases y métodos "no comprobables" en algo más manejable y lo recomiendo encarecidamente.

+0

Veo hacia dónde va y tiene sentido. Simplemente comencé a trabajar en nuevos proyectos y un montón de pruebas de códigos y no unidades. ¿Es un buen trabajo para refactorizar todos estos métodos privados en una clase interna y hacerlos públicos? ¿Es posible probar una clase interna? – user9969

+0

Es posible probar una clase interna utilizando el atributo InternalsVisibleTo, como describió al principio de su pregunta. –

+0

Retomando el resto de la pregunta. La pregunta más profunda es por qué quieres probar a un miembro privado en primer lugar, y por qué quieres que Moq lo haga? –

1

Parece haber dos partes para su pregunta.

  1. ¿Cómo se burlan de un método protegido:

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

  2. ¿cómo puedo activar la invocación de este comportamiento protegida/privada en mi prueba

    La respuesta en este caso es que se desencadenarlo a través de algo público. Si desea forzar que suceda directamente (es decir, invocar realmente algo protected directamente sin un ayudante intermedio, deberá usar la reflexión. Esto es por diseño: los lenguajes proporcionan los mecanismos de protección como una forma de aplicar la encapsulación.

Sin embargo, le sugiero que piense en lo que intenta demostrar/probar en su prueba. Si se encuentra escribiendo una prueba que es complicada, lo está haciendo mal. Quizás lo que quiere hacer puede ser ¿Es posible que esté escribiendo una prueba de integración, no una prueba de unidad? Pero hay muchos artículos sobre pruebas malas, y más tendrá sentido para usted a medida que aprende a escribir buenas pruebas. mis favoritos son http://www.codethinked.com/post/2009/06/30/What-is-Unit-Testing.aspx y http://www.codethinked.com/post/2009/11/05/Ite28099s-Okay-To-Write-Unit-Tests.aspx

+0

gracias por su respuesta. Acabo de unirme a una empresa y han desarrollado toneladas y toneladas de código sin una sola prueba unitaria. Nunca han hecho TDD y cosas similares. Y les resulta difícil explicar el concepto de "no deberían probar un método privado", etc., prueban el comportamiento, no la implementación, etc. ... Ahora, olvidemos por un momento lo que debería y no debería hacer ¿Es posible probar directamente un método privado usando Moq? Parece que he dado todos los pasos necesarios, pero sigo obteniendo respuestas de lo que debería y no debería hacer (lo cual agradezco) pero no ejemplos prácticos. Gracias! – user9969

+0

¡esos enlaces son muy buenos! Me gusta puedo reenviarlos. (Para ayudar a mi caso) – user9969

+0

Ruben, como dije si refactorizar estos métodos internos y hacerlos públicos en clase interna ¿estaré en la misma posición? Solo estoy tratando de pensar en soluciones alternativas que no sean "hacks" – user9969

Cuestiones relacionadas