2008-12-03 12 views
11

Actualmente estoy empezando a introducir el concepto de objetos simulados en mis pruebas unitarias. En particular, estoy usando el framework Moq. Sin embargo, una de las cosas que noté es que de repente las clases que estoy probando usando este marco muestran una cobertura de código de 0%.¿Cómo puedo usar Objetos Simulados en mis pruebas de unidad y todavía utilizar la Cobertura del Código?

Ahora entiendo que, dado que me estoy burlando de la clase, no está ejecutando la clase en sí ... pero, ¿cómo escribo estas pruebas y la Cobertura del código arroja resultados precisos? ¿Tengo que escribir un conjunto de pruebas que usan Mocks y un conjunto para instanciar la clase directamente?

¿Tal vez estoy haciendo algo mal sin darme cuenta?

Aquí es un ejemplo de mí tratando de probar la unidad una clase llamada "MyClass":

using Moq; 
using NUnitFramework; 

namespace MyNameSpace 
{ 
    [TestFixture] 
    public class MyClassTests 
    { 

     [Test] 
     public void TestGetSomeString() 
     { 
      const string EXPECTED_STRING = "Some String!"; 

      Mock<MyClass> myMock = new Mock<MyClass>(); 
      myMock.Expect(m => m.GetSomeString()).Returns(EXPECTED_STRING); 

      string someString = myMock.Object.GetSomeString(); 

      Assert.AreEqual(EXPECTED_STRING, someString); 
      myMock.VerifyAll(); 

     } 

    } 

    public class MyClass 
    { 
     public virtual string GetSomeString() 
     { 
      return "Hello World!"; 
     } 
    } 
} 

¿Alguien sabe lo que debería hacer de manera diferente?

Respuesta

15

No está utilizando sus objetos simulados correctamente. Cuando usa objetos simulados, quiere probar cómo interactúa el código con otros objetos sin utilizar realmente los objetos reales. Ver el código de abajo:

using Moq; 
using NUnitFramework; 

namespace MyNameSpace 
    { 
     [TestFixture] 
     public class MyClassTests 
     { 

      [Test] 
      public void TestGetSomeString() 
      { 
       const string EXPECTED_STRING = "Some String!"; 

       Mock<IDependance> myMock = new Mock<IDependance>(); 
       myMock.Expect(m => m.GiveMeAString()).Returns("Hello World"); 

       MyClass myobject = new MyClass(); 

       string someString = myobject.GetSomeString(myMock.Object); 

       Assert.AreEqual(EXPECTED_STRING, someString); 
       myMock.VerifyAll(); 

      } 

     } 

     public class MyClass 
     { 

      public virtual string GetSomeString(IDependance objectThatITalkTo) 
      { 
       return objectThatITalkTo.GiveMeAString(); 
      } 
     } 

     public interface IDependance 
     { 
      string GiveMeAString(); 
     } 
    } 

No se ve como que está haciendo algo útil cuando el código se acaba volviendo una cadena sin ninguna lógica detrás de él.

El poder real viene si el método GetSomeString() hizo alguna lógica que puede cambiar el resultado de la cadena de salida dependiendo de la devolución del IDependdance. Método GiveMeAString(), luego puede ver cómo su método maneja los datos incorrectos que se envían desde la interfaz IDependdance.

Algo así como:

public virtual string GetSomeString(IDependance objectThatITalkTo { 
    if (objectThatITalkTo.GiveMeAString() == "Hello World") 
    return "Hi"; 
} 

Ahora bien, si usted tiene esta línea en su ensayo:

myMock.Expect(m => m.GiveMeAString()).Returns(null); 

¿Qué pasará con su método de GetSomeString()?

+0

Falta un corchete en el ejemplo de GetSomeString después del parámetro. –

6

Gran error es burlarse del System Under Test (SUT), prueba otra cosa. Deberías burlarte solo de las dependencias SUT.

0

Eso tiene mucho sentido. Esencialmente, usted está diciendo que tengo que estar haciendo lo siguiente:

public class MyClass 
{ 
    public virtual string GetSomeString(MyOtherClass moc) 
    { 
     return moc.ToString(); 
    } 
} 

..... 

Mock<MyOtherClass> myMock = new Mock<MyOtherClass>(); 

MyClass mc = new MyClass(); 

string someString = mc.GetSomeString(myMock.Object); 
Assert.AreEqual(EXPECTED_STRING, someString); 

crear instancias de esencialmente el SUT y sólo usando burla para las clases del SUT requiere?

+0

Además, su método GetSomeString ahora tendrá cobertura porque está llamando al GetSomeString real, pero solo con un objeto falso que necesita para que no vaya más allá y lanzando misiles que no conoce :) Todo se trata de probar de forma aislada. –

2

Recomendaría que se mantenga alejado de los marcos de burla hasta que comprenda las interacciones que están ocurriendo aquí.

IMO es mejor aprender con los dobles de prueba creados manualmente, luego pasar a un marco de burla después. Mi razonamiento:

  1. Mocking frameworks resumen lo que está sucediendo realmente; es más fácil captar las interacciones si tiene que crear sus dependencias explícitamente, luego siga las pruebas en el depurador.

  2. Es fácil hacer un mal uso de los marcos. Si gana el suyo propio cuando está aprendiendo, es más probable que comprenda las diferencias entre los diferentes tipos de dobles de prueba. Si vas directamente a un marco burlón, es fácil usar simulaciones cuando quieres talones y viceversa, hay una gran diferencia.

Piénselo de esta manera: la clase bajo prueba es el enfoque. Usted crea una instancia de la misma, llama a sus métodos y luego afirma que el resultado es correcto. Si la clase bajo prueba tiene dependencias (por ejemplo, se requiere algo en el constructor), usted satisface esas dependencias usando A: clases reales o B: prueba de dobles.

La razón por la que usamos test doubles es que aísla la clase bajo prueba, lo que significa que puede ejercer su código de una manera más controlada.

E.g. si tiene una clase que contiene un objeto de red, no puede probar las rutinas de manejo de errores de la clase propietaria que detectan conexiones inactivas si se ve obligado a utilizar un objeto concreto de conexión de red. En su lugar, inyectas un objeto de conexión falso y le dices que haga una excepción cuando se llama al método "SendBytes".

I.e. En cada prueba, las dependencias de la clase bajo prueba se crean específicamente para ejercitar una pieza de código en particular.

Cuestiones relacionadas