> For the complete documentation index, see [llms.txt](https://elguerre.gitbook.io/de0an/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://elguerre.gitbook.io/de0an/capitulo-6-la-construccion.-testeando-desde-el-principio/pruebas-unitarias.md).

# Pruebas Unitarias

Como su nombre indica, las pruebas unitarias son un conjunto de pruebas que validan unitariamente el correcto funcionamiento del código. Deberán definirse al menos, para cada método público de una clase o módulo. Tendremos en cuenta algunos aspectos importantes:

1. Definiremos un conjunto/casos de pruebas a realizar para cada requisito, definidas generalmente tras la finalización del diseño técnico.
2. La automatización de las mismas asegurará que el código funciona correctamente ante constantes cambios y, comúnmente durante el desarrollo. Permitirán detectar defectos, así como reducir el tiempo de detección de éstos, principalmente durante su posterior mantenimiento.
3. Las pruebas deberán aportar información medible con objeto de saber en todo momento si:
   1. La ejecución de las mismas se ha realizado con éxito.
   2. Las líneas de código que cubren, es decir, la **cobertura de código**, ronda al menos, el 60%.
   3. El mantenimiento del código es lo suficientemente bajo, de forma que su **índice de mantenibilidad** es superior a 20. A mayor índice, mejor mantenimiento. La siguiente tabla ilustra estos valores:

**Tabla 1.- Indicadores del índice de mantenibilidad**

| Icono                                                                                                                                                                                                | Índice   | Valor    |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------- |
| ![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-72fe44cbd45afadfa999af9bb59633a721e0e3de%2Fimage5.png?alt=media) | 0-9      | Rojo     |
| ![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-6d64ae5f9dc942b0e10d1a1859323f7f66877104%2Fimage6.png?alt=media) | 10 – 19  | Amarillo |
| ![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-cc904cd0ad9c12292d0bb1b9fb7b7c736d0d96bb%2Fimage7.png?alt=media) | 20 – 100 | Verde    |

4. La **complejidad ciclomática**, que mide cuantitativamente la complejidad lógica de un programa. Se refiere al número de pruebas totales que hay que realizar para cubrir el 100% del código, es decir, el número de caminos diferentes en el flujo del programa (sentencias *if*, *for*, *while*, *case*, etc.). El riesgo que suponen se puede determinar utilizando una serie de rangos que podemos ver definidos en la siguiente tabla:

**Tabla 2.- Indicadores de complejidad ciclomática en función del riesgo**

| Complejidad ciclomática | Evaluación del riesgo            |
| ----------------------- | -------------------------------- |
| 1-10                    | Programa Simple, poco riesgo     |
| 11-20                   | Riesgo moderado                  |
| 21-50                   | Complejo. Alto riesgo            |
| > 50                    | Testeo inviable. Muy alto riesgo |

Cuando la complejidad de un programa supera el valor de 10, se hace muy difícil probarlo, entenderlo y modificarlo.

En las siguientes secciones entraremos en detalle en estos aspectos y aprenderemos cómo desde Visual Studio tenemos acceso a todas estas medidas.

## Análisis de código

Se trata de un análisis de ensamblados (administrados) basado en la validación de un conjunto de reglas de programación que advierten de infracciones (o violaciones) relacionadas con el diseño, globalización/localización, interoperabilidad, rendimiento, seguridad y otros problemas potenciales.

De la misma forma pueden servirnos de guías en las buenas prácticas de desarrollo, como, por ejemplo, para la documentación del código, variables no usadas o no asignadas, etc.

Visual Studio tiene predefinidas muchas de estas reglas, y otras, pueden ser personalizadas según las necesidades de cada proyecto/aplicación.

La **configuración** del análisis se encuentra en las propiedades de cada proyecto, concretamente, en la pestaña “Code Analysis”, donde seleccionaremos los diferentes conjuntos de reglas para el análisis de nuestro código.

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-9b49114d841a8ad7ceb31399d69fcd8f4d84db2a%2Fimage8.PNG?alt=media)

**Figura 04.- Configuración del análisis de código para un proyecto**

Marcando la casilla “Enable Code Analysis on Build” podremos ejecutar automáticamente el análisis de código en cada una de nuestras compilaciones y pulsando el botón “Open”, accederemos a la ventana de edición /selección de reglas según podemos ver en la siguiente figura:

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-a11fe3c13769caae30c4c9e86be93b55a7f1d56d%2Fimage9.png?alt=media)

**Figura 05.- Edición de reglas de código desde Visual Studio**

De la misma manera que para un proyecto, podemos seleccionar el conjunto de reglas, para la solución completa lo conseguimos mediante la opción de menú: “Analyze – Configure Code Analysis - For Solution”.

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-f847d1496141ed97b14905b10c0db84a02bc7d84%2Fimage10.png?alt=media)

**Figura 06.- Configuración del análisis de código para la solución**

La **ejecución** del análisis, la llevaremos a cabo mediante de la opción de menú contextual de cada proyecto: “Analyze – Run Code Analysis” o, a nivel de solución: “Analyze – Run Code Analysis On Solution”, o incluso a través del atajo de teclado, “Alt + F11”.

Cada una de las infracciones cometidas, pueden resolverse adecuadamente o bien, suprimiéndola, donde para ello utilizaremos la instrucción “SupressMessage” de forma similar a como ya vimos en el capítulo 5.

```csharp
[System.Diagnostics.CodeAnalysis.SuppressMessage(
    "Await.Warning",
    "CS4014:Await.Warning",
    Justification="El método FeedbackService.CheckRateReminderAsync
    debe mostrar el mensaje de valoración al usuario sin que se
    interrumpa el inicio de la aplicación"
    )]
{
    …
}
```

En este código, como ya adelantamos en el capítulo 5, podemos observar la invalidación de una regla para el método *OnStartAsync* de la clase *App.xaml.cs*. Como recomendación, para cualquier invalidación indicaremos siempre la justificación (*Justification*) de su anulación. Así, siempre sabremos el motivo.

Para poder ejecutar el análisis de código de manera automática en las builds, activaremos la casilla “Enable Code Analysis on Build” en las propiedades de proyecto, tanto para la configuración “Debug” como para la configuración “Release”:

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-67a3b7928798f4ca06b52dee9153ca33e1649a13%2Fimage11.png?alt=media)

**Figura 07.- Habilitar el análisis de código en las builds**

Si es necesario, otorgaremos permisos al usuario que lanza la *build* para que pueda ejecutar el análisis de código. En caso de ser administradores omitiremos este paso.

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-b6832c4a012368ee42c1acf58c8bc6381086e787%2Fimage12.png?alt=media)

**Figura 08.- Habilitar permisos en VSTS para la ejecución de builds con análisis de código**

Además de las reglas predefinidas en Visual Studio existen otras herramientas tales como StyleCop, *OpenCover*, *JetBrains* *dotCover*, *NCover*, etc., que nos facilitan la codificación de nuevas reglas. Así mismo, Visual Studio también cuenta con las plantillas del SDK de la plataforma del compilador de .NET (o *.NET Compiler Platform SDK Templates*) que encontraremos en este enlace: <https://learn.microsoft.com/es-es/dotnet/csharp/roslyn-sdk/>.

## Métricas de código

Como ya hemos comentado anteriormente, las métricas van a permitirnos realizar una medición del código con el fin de identificar qué acciones deberíamos tomar para mejorarlo.

En Visual Studio realizaremos el cálculo de métricas, a través de la opción “Calculate Code Metrics” del menú contextual de proyecto, o bien, desde el menú “Analyze - Calculate Code Metrics”. Tras su ejecución obtendremos un resultado en formato tabular similar al que podemos ver en la siguiente figura.

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-641f5b5f4efd6bada7fab928f48e37ae953083f7%2Fimage13.png?alt=media)

**Figura 09.- Cálculo de métricas de código con Visual Studio**

A modo de ejemplo, se ha expandido la clase *AboutViewModel*, para la que podemos observar que los valores: Índice de Mantenibilidad (o *Maintainability Index*) y Complejidad Ciclomática (o *Cyclomatic Complexity*) se encuentran dentro de los recomendados y, por tanto, podemos decir que nuestros métodos poseen una buena calidad. Habrá ocasiones en la que esto no sea así y, será en este punto donde deberemos prestar especial atención al número de líneas de código. Por ejemplo, una complejidad ciclomática elevada para un método con un alto número de líneas de código, nos indicará claramente que el método hay que *refactorizarlo*.

Existen otros dos valores también importantes:

* La profundidad de herencia (o *Depth of Inheritance)*. Número de niveles de una jerarquía de clases. A mayor profundidad, menor legibilidad de código.
* Acoplamiento (o *Class coupling*). Interrelación entre clases. Conocimiento que una clase tiene del detalle de otra. Si el acoplamiento es alto (también denominado fuerte), la legibilidad del código se ve incrementada. Asociado a éste, se encuentra la **cohesión**, que indica si cada clase tiene correctamente definida su responsabilidad y no existen responsabilidades mezcladas en una misma clase. Caso en el que habría que crear tantas clases como responsabilidades hubiera. Hablaremos, por tanto, de bajo acoplamiento y alta cohesión para referirnos a un código con alta reutilización y fácil mantenimiento.

Es de vital importancia prestar especial atención a los resultados de las métricas para métodos anónimos (o métodos sin nombre), que serán asociados al método que los declara.

## Cobertura de código

Se trata de otro conjunto de métricas que evalúan el grado en que nuestro código es probado (o testeado). Determinan la calidad de las pruebas proporcionando información sobre qué parte de código ha sido probada y qué parte no y, pueden ser utilizadas como técnica para la eliminación de código no usado.

{% hint style="info" %}
**Nota**: En el momento de escribir el libro, no existe la posibilidad de calcular la cobertura de código para aplicaciones Universales (UWP) por lo que se ha optado por ejemplificar su uso a través de una pequeña demo “.**NoUWP**”.
{% endhint %}

Ejecutaremos la cobertura en Visual Studio siguiendo estos pasos:

* Seleccionar la opción de menú: “Test – Analyze Code Coverage” y seguidamente:
  * “Selected Tests”, para los test seleccionados en el “Test Explorer”,
  * “All Tests”, para todos los tests de la solución.

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-6f5afd4172b8e3d83d88d62fae1d45779dd2f76d%2Fimage14.png?alt=media)

**Figura 10.- Análisis de cobertura de código**

* Una vez completado el proceso, podemos revisar el estado de la cobertura de código por espacio de nombres, módulo, clase y/o método.

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-c72f09ae42472bb2b8fb344c4023e6f740a22446%2Fimage15.png?alt=media)

**Figura 11.- Resultado del análisis de cobertura de código**

También podemos chequear qué porción de código ha sido probada y qué porción no, Visual Studio marca el código con los colores azul y rojo, indicando así que el código ha sido probado o no respectivamente. Para ello, bastará con pulsar el botón ( ![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-d642004ecaeb6cb80222a9954ae7ec8bad4dedfa%2Fimage16.PNG?alt=media)) de la ventana de resultados y seleccionar la clase a contrastar.

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-1302390557bec759bd044f218598dd9639188c9a%2Fimage17.png?alt=media)

**Figura 12.- Coloración tras el análisis de cobertura de código**

Igualmente, el botón (![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-9e8d87f6c3e90418f8932aca0ca3d6afe19aa187%2Fimage18.PNG?alt=media)) fusionará las distintas ejecuciones de la cobertura de código y nos permitirá comprobar las diferencias entre una y otra pudiendo chequear su evolución.

Para que la cobertura de código alcance su potencial, es imprescindible estudiar su evolución en relación a los cambios/renovación de código (*code churn*) que vamos realizando, así como el número de bugs que se van produciendo. Las builds en VSTS generan un resultado como el que podemos ver en la siguiente figura donde además de indicarnos el porcentaje de cobertura, nos indica los bloques de código que se han cubierto con las mismas:

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-219bd8f1af0841f23bbea61c5b4e56911866371c%2Fimage19.png?alt=media)

**Figura 13.- Resultado de la ejecución de una build**

En el momento de escribir el libro, VSTS no ofrece más detalle, por lo que para conseguirlo tendríamos que utilizar Team Foundation Server (TFS). A continuación, podemos ver algunos ejemplos sobre cómo sería este tipo de informes.

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-d1bde035f70826e3a13b00ada4f969d1d3af8f1f%2Fimage20.png?alt=media)

**Figura 14.- Informe sobre la calidad de las Builds con TFS**

De esta misma manera, las *builds* muestran su progreso, estado de la cobertura (si ésta es suficiente, si incrementa o disminuye), y el cambio/renovación de código.

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-65b90a8cfaec1d539f6f2a7951713ce97fc6c19f%2Fimage21.png?alt=media)

**Figura 15.- Resumen de la ejecución de varias Builds con TFS**

Para más información sobre estos informes podemos visitar la página: <https://msdn.microsoft.com/es-es/library/dd380714.aspx>

{% hint style="info" %}
**Nota**: La potencia de la cobertura de código, así como del resto métricas se alcanza cuando **estudiamos su evolución**. Éste es el aspecto clave y más relevante que conseguiremos gracias a Visual Studio y VSTS o Team Foundation Server. Para el caso de la cobertura de código, es importante, por tanto, estudiar dicha evolución y no únicamente el porcentaje de la misma, que por sí sola no es un indicador suficiente.
{% endhint %}

## Mocks

*Mocks*, *stubs*, *dummies* y *fakes*, son muchos de los nombres que reciben los componentes que simulan el comportamiento de objetos. Entre otras funcionalidades, sustituyen aquellos sistemas que durante el entorno de desarrollo no se encuentran accesibles.

Desarrollaremos *mocks* para suplir la funcionalidad de dichos sistemas. Un caso muy común pueden ser los proveedores (o *providers)* de acceso a datos: *Storage*, *SQLLite* o *OneDrive* entre otros. Es decir, desde el momento en que comenzamos a desarrollar podemos crear un *mock* para cada uno de estos proveedores y olvidarnos de su implementación hasta que un compañero o nosotros mismos podamos completarlo. Lo importante es saber, que en todo momento el código que use cada proveedor podrá estar probado con la calidad oportuna.

Como ya sabemos, los utilizaremos también para implementar los *ViewModelsMocks* con el propósito de tener datos ficticios durante el tiempo de diseño. Así, simularemos el comportamiento de propiedades públicas enlazadas (o *bindadas*) con la vista (*Views*).

Cuando desarrollamos pensando en los Mocks, utilizamos principalmente interfaces. De esta manera podemos trabajar fácil e indistintamente tanto con el componente real como con uno ficticio durante las pruebas. A éstos se les denominan concretamente **stubs**. Sin embargo, hay ocasiones, en las que los componentes ya están desarrollados y éstos no disponen de las interfaces requeridas. Es en este caso, donde necesitamos un framework para que realmente nos facilite el trabajo. En Visual Studio contamos de manera nativa, con **Fakes**, conocidos también en versiones anteriores como *Moles*.

En el momento de escribir el libro, no es posible generar Fakes para aplicaciones Universales. Conseguiremos un resultado similar, gracias a los métodos anónimos “Action<>” y “Func<>”. Concretamente, el uso de “Func<>”, ya lo conocimos en el capítulo 5, lo utilizaremos, por tanto, en el método *Initialize*, de la clase *ViewModelBase*, para simular una carga de datos o, proporcionar un listado de valores estáticos en cada *ViewModel*.

No obstante, conozcamos mediante un ejemplo práctico, cuáles serían los pasos necesarios para trabajar con *Fakes*:

1. Supongamos un servicio web con un método *HasCertificate*, que indica si éste tiene o no certificado y cuyo código es el siguiente:

```csharp
public class Service
{
    public bool HasCertificate()
    {
        bool result =
            HttpContext.Current.Request.ClientCertificate.IsPresent;
        return result;
    }
}
```

Estamos haciendo uso de un contexto HTTP para validar la existencia del certificado de nuestro servicio. Al tratarse de un contexto HTTP no podemos usarlo en las pruebas unitarias dado que dicho contexto no existe. Generaremos, por tanto, un *Fake* para simular esta necesidad:

1. Sobre las referencias de la que queremos obtener la simulación, seleccionar la opción del menú contextual: “Add Fakes Assembly”. Por ejemplo, “System.Web”:

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-497ff7eabd9105bb885641cad7726e70e82ca1bd%2Fimage22.png?alt=media)

**Figura 16.- Opción "Add Fakes Assembly" en el menú contextual de la referencia System.Web**

2. Para la referencia seleccionada, se auto-genera:
   1. Una nueva referencia “Microsoft.QualityTools.Testing.Fakes”, en caso de no existir.
   2. Una nueva carpeta *Fakes*, siempre que no exista previamente.
   3. Un nuevo fichero de tipo XML, “System.Web.Fakes”, que se añade en la carpeta *Fakes* anterior.

      ![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-7a918dff2444c9b221dffd9810b8a05a52337418%2Fimage23.png?alt=media)

      **Figura 17.- Fichero "System.Web.Fakes" generado en la carpeta Fakes del proyecto**
   4. Y, tras compilar el proyecto se genera una nueva referencia “System.Web.4.0.0.0.Fakes”
3. A continuación, creamos la clase de pruebas tal y como sigue:

```csharp
[TestInitialize]
public void InitializeTest()
{
    ShimsContext.Create();
    var httpRequest =
        new HttpRequest("","http://tempuri.org", "");
    var httpContext =
        new HttpContext(httpRequest,
            new HttpResponse(new StringWriter()));
    ShimHttpContext.CurrentGet =
        () => { return httpContext; };
    ShimHttpClientCertificate.ConstructorHttpContext =
        (o, httpCont) => { };
    ShimHttpClientCertificate.AllInstances.IsPresentGet =
        (o) => { return true; };
}
```

Donde el método inicializador, *InitializeTest(),* se encarga de iniciar todos los métodos y propiedades *fakes* necesarios para simular el contexto HTTP completo: *HttpContext*, *Current*, *ClientCertificate* e *IsPresent*.

4. Finalmente, añadimos el método de prueba (*TestMethod*) generando una instancia del servicio y llamando al método *HasCertificate()*, como si del servicio real se tratara. El contexto HTTP ficticio se encargará de hacer el resto.

```csharp
[TestMethod]
public void HasCertificateTest()
{
    Service service = new Service();
    bool exists = service.HasCertificate();
    Assert.IsTrue(exists, "Certifate not present!");
}
```

De esta misma manera, podríamos seguir probando el resto de métodos abstrayéndonos de la implementación de *HttpContext*, y centrarnos, únicamente, en probar la lógica de las clases y métodos que estamos desarrollando.

Para más detalle sobre la generación de *Fakes*, visitar la página: <https://msdn.microsoft.com/es-es/library/hh708916.aspx>.

{% hint style="info" %}
**Nota**: Además de todas las pruebas, cobertura de código, métricas y *mocks*, una buena práctica es documentar el código. Transcurridos unos meses, semanas o incluso días, olvidaremos con facilidad lo escrito, y, más importante aún, el por qué lo hicimos.

Recordemos que el “refactoring” forma parte de la calidad de nuestro código y es una tarea recurrente que no debemos pasar por alto.

Recordemos también, desarrollar el código pensando en un mantenimiento posterior. ¡Seamos eficaces y nos ahorraremos bastantes dolores de cabeza además de ganar en calidad!
{% endhint %}

## Proyecto de pruebas unitarias

Una vez repasados los conceptos principales sobre pruebas unitarias veamos cómo implementar nuestro proyecto de Test:

1. Añadir a la solución un proyecto de tipo “Unit Test App (Universal Windows)” indicando como nombre “ElGuerre.Taskin.Uwp.Tests”.
2. Añadir la referencia al proyecto principal “ElGuerre.Taskin.Uwp”
3. Reemplazar la carpeta *Assets* por *AssetsTests*, lo que evitará errores por duplicidad de recursos, entre el proyecto *Uwp* y *Uwp.Test*.
4. Reemplazar en código, la ruta de las imágenes para utilizar *AssetsTests*.
5. Añadir los paquetes NuGet: *MvvmLightLibs* y *Template10*.
6. Crear una carpeta *ViewModels* y añadir una nueva clase *AboutViewModeText.cs* con el siguiente código:

```csharp
[TestClass]
public class AboutViewModelTest
{
    private static IAboutViewModel viewModel;
    public TestContext TestContext { set; get; }
    [ClassInitialize]
    public static void TestClassInitialize(TestContext testContext)
    {
        viewModel =
            ViewModelLocator.Current.GetInstance<IAboutViewModel>();
    }
    [ClassCleanup]
    public static void TestClassCleanup()
    {
        viewModel = null;
    }
    [TestInitialize]
    public void TestInitializeTest(){}
    [TestCleanup]
    public void TestCleanupTest(){}
    [TestMethod]
    public void SectionsTest()
    {
        var sections = viewModel.Sections;
        Assert.IsNotNull(sections, "Secctions cannot be null");
        Assert.AreEqual(3,
            sections.Length,
            "Any of expected sections not found.");
    }
    [TestMethod]
    public void AboutViewModelConstructorTest()
    {
        Assert.IsNotNull(viewModel,
            "AboutViewModel instance not created !");
    }
    [TestMethod]
    public void MitLicenseTest()
    {
        var txt = viewModel.MitLicense;
        Assert.IsTrue(!String.IsNullOrWhiteSpace(txt),
            "Mit license cannot be null or empty");
    }
    [TestMethod]
    public void MitLicenseHeaderTest()
    {
        var txt = viewModel.MitLicenseHeader;
        Assert.IsTrue(!String.IsNullOrWhiteSpace(txt),
            "Mit license Header cannot be null or empty");
    }
    ...
}
```

7. Ejecutar las pruebas desde el explorador (“Test Explorer”)

![](https://240651724-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfrvHBNivOTy0fVKROgzo%2Fuploads%2Fgit-blob-aba5debd97458afb9374abaa700ff1e536ee6583%2Fimage24.png?alt=media)

**Figura 18.- Ejecución de pruebas para la clase AboutViewModelTest**

Al igual que para la clase *AboutViewModel*, continuaremos creando pruebas de esta misma manera para el resto de ViewModels, así como para las clases: *converters*, *helpers*, clases comunes, etc.
