Pregunta

Actualmente estoy empezando a introducir el concepto de objetos simulados en mis pruebas unitarias. En particular, estoy usando el marco Moq. Sin embargo, una de las cosas que he notado es que de repente las clases que estoy probando usando este marco muestran una cobertura de código del 0%.

Ahora entiendo que dado que me estoy burlando de la clase, no está ejecutando la clase en sí misma ... pero, ¿cómo escribo estas pruebas y hago que la Cobertura del Código arroje resultados precisos? ¿Tengo que escribir un conjunto de pruebas que usan simulacros y un conjunto para crear una instancia de la clase directamente.

¿Quizás estoy haciendo algo mal sin darme cuenta?

Aquí hay un ejemplo de mí tratando de probar la unidad en 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?

¿Fue útil?

Solución

No estás usando tus objetos simulados correctamente. Cuando usas objetos simulados, querías probar cómo tu código interactúa con otros objetos sin usar realmente los objetos reales. Vea el código a continuación:

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 parece que esté haciendo nada útil cuando su código solo devuelve una cadena sin ninguna lógica detrás de ella.

El poder real se obtiene si el método GetSomeString () realizó alguna lógica que puede cambiar el resultado de la cadena de salida dependiendo del retorno de IDependdance . GiveMeAString () , entonces 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 si tiene esta línea en su prueba:

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

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

Otros consejos

Un gran error es burlarse del System Under Test (SUT) , prueba algo más. Solo debes burlarte de las dependencias SUT.

Recomiendo mantenerse alejado de los frameworks burlones hasta que comprenda las interacciones que están ocurriendo aquí.

En mi opinión, es mejor aprender con dobles de prueba creados manualmente, y luego pasar a un marco burlón. Mi razonamiento:

  1. Los marcos de burla abstraen lo que realmente está sucediendo; es más fácil comprender las interacciones si tiene que crear sus dependencias explícitamente, luego siga las pruebas en el depurador.

  2. Es fácil usar mal los frameworks. Si saca el suyo cuando está aprendiendo, es más probable que comprenda las diferencias entre los diferentes tipos de dobles de prueba. Si va directamente a un marco burlón, es fácil usar simulacros cuando quería trozos y viceversa, hay una gran diferencia.

Piénselo de esta manera: la clase bajo prueba es el enfoque. Crea una instancia de él, 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 utilizando A: clases reales o B: dobles de prueba.

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

Por ejemplo. 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 usar un objeto de conexión de red concreto. En su lugar, inyecta un objeto de conexión falso y le dice que arroje una excepción cuando su " SendBytes " Se llama al método.

I.e. En cada prueba, las dependencias de la clase bajo prueba se crean específicamente para ejercer un código particular.

Eso tiene mucho sentido. Básicamente estás diciendo que necesito hacer 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);

¿Esencialmente crear instancias del SUT y solo usar simulacros para las clases que requiere el SUT?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top