Por norma general los desarrolladores (y por supuesto los testers 😉 ) ocupan mucho tiempo de su jornada para probar el código y asegurarse que la funcionalidad esta implementada correctamente y cumple con la finalidad para la que haya sido diseñada la aplicación.
TDD
Tdd, es la abreviatura de Test Driven Development (Desarrollo Orientado a Pruebas) y es una metodología donde se contempla el ciclo de vida del desarrollo de software de la siguiente forma (y orden):
- Creación de la pruebas unitarias o unit testing
- Implementación del código que está probando la prueba
- Refactoring del código anteriormente implementado
Para que esta metodología funcione, el código tiene que estar lo suficiente estructurado como para poder crear unit test que prueben pequeñas partes de la funcionalidad.
Vamos a ver un ejemplo práctico
Vamos a ver un ejemplo práctico que es como mejor se ve todo. Vamos a crear una entidad y un objeto de negocio, y vamos a probar el constructor de la entidad y un método del objeto de negocio.
Las pruebas unitarias o unit test los vamos a tener en un proyecto del tipo Class Library, con la peculiaridad de que a las clases que sean pruebas les tendremos que añadir el argumento TestClass y a los métodos el argumento TestMethod. Sería algo así:
[TestClass()]
public class LinkInfoTest
[TestMethod()]
public void LinkInfoConstructorTest()
Un proyecto de Test no tiene pq tener unicamente pruebas unitarias, tambien puede tener otros tipos de test como WebTest (por ejemplo).
La prueba unitaria del constructor, tiene que probar que ninguno de los miembros queda con un valor nulo y que los valores pasados al mismo se asignan correctamente. Vamos a ver la implementación:
[TestMethod()]
public void LinkInfoConstructorTest()
{
string expectedText = "a deshoras";
string expectedTitle = "ir a a deshoras (https://adeshoras.wordpress.com/)";
string expectedHRef = "https://adeshoras.wordpress.com/";
LinkInfo actualLinkInfo = new LinkInfo(expectedText, expectedTitle, expectedHRef);
Assert.IsTrue(!string.IsNullOrEmpty(actualLinkInfo.Text));
Assert.IsTrue(!string.IsNullOrEmpty(actualLinkInfo.Title));
Assert.IsTrue(!string.IsNullOrEmpty(actualLinkInfo.HRef));
Assert.AreEqual(expectedText, actualLinkInfo.Text);
Assert.AreEqual(expectedTitle, actualLinkInfo.Title);
Assert.AreEqual(expectedHRef, actualLinkInfo.HRef);
}
Y ahora vamos a implementar nuestra entidad. Vamos a necesitar 3 miembros y un constructor al que se le pasan 3 valores y lo asigna. Aparte de esto le voy a añadir 3 propiedades publicas y un constructor por defecto. El aspecto de la entidad sería el siguiente:
public class LinkInfo
{
#region members
private string _text;
private string _title;
private string _href;
#endregion
#region properties
public string Text
{
get { return _text; }
set { _text = value; }
}
public string Title
{
get { return _title; }
set { _title = value; }
}
public string HRef
{
get { return _href; }
set { _href = value; }
}
#endregion
#region constructor
public LinkInfo() { }
public LinkInfo(string text, string title, string href)
{
_text = text;
_title = title;
_href = href;
}
#endregion
}
Vamos ahora a por el objeto de negocio. Vamos a implementar la prueba de un método que nos devuelva una colección de LinkInfo a partir de un XElement (que recibira el método como parámetro).
Para empezar el xml que vamos a necesitar lo vamos a almacenar en un archivo de recursos, de manera que despues lo podemos parsear a traves de un string. El xml tiene este aspecto:
<?xml version="1.0" encoding="utf-8" ?>
<LinkList>
<Link>
<Text>
<![CDATA[Así se fundo Carnaby Street]]>
</Text>
<Title>
<![CDATA[Así se fundo Carnaby Street]]>
</Title>
<HRef>
<![CDATA[http://carnabys.blogspot.com/]]>
</HRef>
</Link>
<Link>
<Text>
<![CDATA[Búscate un novio]]>
</Text>
<Title>
<![CDATA[Búscate un novio]]>
</Title>
<HRef>
<![CDATA[http://buscateunnovio.blogspot.com/]]>
</HRef>
</Link>
<Link>
<Text>
<![CDATA[El blog de la nadadora]]>
</Text>
<Title>
<![CDATA[El blog de la nadadora]]>
</Title>
<HRef>
<![CDATA[http://lanadadora.blogspot.com/]]>
</HRef>
</Link>
</LinkList>
El unit test de este método (que vamos a llamar GetLinks), va a probar que el método no devuelve un valor nulo y que el número de items de la lista devuelta va a ser tres. Vamos a verla:
[TestMethod()]
public void GetLinksTest()
{
LinkBC linksBC = new LinkBC();
List<LinkInfo> links = null;
XElement xmlData = XElement.Parse(Resources.XMLData.Links);
links = linksBC.GetLinks(xmlData);
Assert.IsNotNull(links);
Assert.AreEqual(3, links.Count);
}
Como nota aclaratoria, LinkBC, es el nombre de la clase que contiene el método GetLinks que es el que estamos probando.
Y ahora que ya tenemos la prueba, tenemos que implementar el método, así que añadiremos una nueva clase cuyo nombre sera LinkBC y ahí crearemos un método publico que se encarge de devolver una colección de LinkInfo a partir de un XElement pasado commo parametro. Vemos el aspecto del método:
public List<LinkInfo> GetLinks(XElement xmlData)
{
IEnumerable<LinkInfo> links = from node in xmlData.Descendants(NODE_LINK_NAME)
select new LinkInfo
{
Text = ((XElement)node.Element(NODE_TEXT_NAME)).Value,
Title = ((XElement)node.Element(NODE_TITLE_NAME)).Value,
HRef = ((XElement)node.Element(NODE_HREF_NAME)).Value
};
return new List<LinkInfo>(links);
}
Como veis, por medio de linq, vamos a devolver la lista indicada.
Ahora solo nos queda pasar la prueba y ver que funciona que esta en verde y antes de nada hagamonos una pregunta: ¿Cómo sabemos que los LinkInfo, se estan creando correctamente? o ¿Por qué no probamos la creación de LinkInfo?. Pues muy sencillo, en el unit test anterior, solo estamos probando el cometido de este metodo que es hacer la consulta linq y devolver correctamente la lista, mientras que en el Unit Test de la clase, es donde tenemos que probar que las entidades se crean correctamente.
El código de ejemplo, lo he realizado con Visual Studio 2008 Team System y asp.net framework 3.5, dado que quería usar las consultas linq (si sois asiduos a este blog, este código de ejemplo se uso practicamente igual para mostrar como funcionabla Linq To Xml). Con Visual Studio, es con esta versión con la primera que se podían crear pruebas unitarias de forma “automática”, pero anteriormente tambien podíamos crear nuestros test con frameworks “externos” como por ejemplo NUnit.
El código de ejemplo lo teneis aquí (ved que he cambiado el sitio donde subo los arhivos y ahora es más intuitiva la descarga) como siempre y os recomiendo que os lo bajeis y que debugueis y veais que todo funciona ok y que si teneis un comentario o problema o duda o lo que sea pues no dudeis en preguntar y veremos si entre todos la podemos aclarar.
Y ahora me despido, que tengo una cita, no sin antes dejaros una imagen (que como dicen por ahí vale más que mil palabras) que muestra como se tienen que quedar las pruebas (en verde claro) y que más adelante veremos como probar objetos más complejos con los Mocks.
Operadores de Linq: Como usar los operadores Take, StartsWith, EndsWith y Contains « a deshoras