Aprovecho que en los últimos días los compañeros Luís Ruiz Pavón y Bruno Capuano han escrito sendos artículos sobre Moles ( aquí y aquí ) para hacer una pequeña introducción a otro framework de mocking llamado Moq.
Lo primero que tenemos que hacer es bajarnos la dll de su web . Una vez hecho esto ya podemos incluir la librería (Moq.dll ) en nuestro proyecto de test.
El código que vamos a testear se compone de una clase llamada AssetManager que tiene una dependencia a IDAO, una interfície para definir la manera en que se persistirán los objetos, ya sea en una base de datos, en un fichero o en memoria. Es esta interfície la que "mockearemos", evitando así tener que codificar una implementación para testear AssetManager.
Lo primero que vamos a hacer es crear un stub para la función SaveAsset de IDAO. Para tener clara la diferencia entre un Mock y un Stub, consulta este artículo de Martin Fowler.
Veamos el código para testear esta función:
[TestMethod]
public void SaveAsset_returns_true()
{
var mockDao = new Mock<IDAO>();
AssetManager assetManager = new AssetManager(mockDao.Object);
Asset asset = new Asset();
mockDao.Setup(dao => dao.SaveAsset(asset)).Returns(true);
Assert.AreEqual(true, assetManager.SaveAsset(asset));
}
Como podemos ver estamos creando un stub de nuestra interfície IDAO indicando que cuando se llame a la función SaveAsset nos devuelva el valor true. Así, al invocar al método SaveAsset de la clase AssetManager, que a su vez llama al método SaveAsset de la interfície IDAO, nos devolverá true y el test pasará. Para comprobar que esto es cierto, basta con cambiar el valor de retorno de la función de IDAO y veremos que el test no pasa.
En el ejemplo anterior, nada nos garantiza que realmente se haya llamado a la función de IDAO, ya que SaveAsset de AssetManager podria haber devuelto true directamente. Ahora vamos a ver como podemos "mockear" una función y verificar que realmente se llama:
[TestMethod]
public void GetAssetByName()
{
var mockDao = new Mock<IDAO>();
AssetManager assetManager = new AssetManager(mockDao.Object);
assetManager.GetAssetByName("MyFirstAsset");
mockDao.Verify(dao => dao.GetAssetByName("MyFirstAsset"));
}
Como podemos ver claramente en el código, con la función Verify verificamos que se haya llamado a la función GetAssetByName de la interficie IDAO con el parámetro MyFirstAsset. Podemos comprobar que esto es cierto modificando el string "MyFirstAsset" de una de las dos llamadas por otro string. El resultado será que el test no pasará. Este tipo de cosas puede hacer que nuestro test sea demasiado frágil y, por lo tanto, difícil de mantener. Moq nos ofrece la classe It para lidiar con este tipo de problemas. Podriamos substituir el string "MyFirstAsset" por sentencias del tipo:
-
It.IsAny<string>() -> pasa como parámetro cualquier string
-
It.Is<string>(s => s.StartsWith("My")) -> pasa como parámetro un string que empieza por "My"
-
It.IsRegex("\ba") -> pasa como parámetro un string que empieza por la letra a
Al igual que podemos comprobar que se ha llamado a una función, quizá también nos pueda interesar comprobar que se ha seteado una propiedad. Para hacerlo, nos apoyaremos en la función VerifySet del mock:
[TestMethod]
public void Verify_ConnectionString_was_set()
{
var mockDao = new Mock<IDAO>();
AssetManager assetManager = new AssetManager(mockDao.Object);
mockDao.VerifySet(x => x.ConnectionString = It.Is<string>(s => s.StartsWith("Non")));
}
Con este código comprobaremos que se ha seteado la propiedad ConnectionString con un valor que empieza por "Non".
Y por hoy ya tenemos suficiente. Hemos visto que es muy fácil utilizar Moq y hacer los primeros pasos con él. En posteriores tutoriales veremos más características de este framework.
Hasta la próxima!