vs2015 visual unitarias unitaria studio pruebas prueba net mvc las hacer con arquitectura aplicaciones asp.net testing automated-tests functional-testing web-testing

asp.net - visual - Integración de pruebas web automatizadas en el proceso de construcción



pruebas unitarias en c# con vs2015 (6)

¿Por qué necesitas copiar código? Olvídate de Cassini y deja que Visual Studio cree un directorio virtual para ti. Seguro que los desarrolladores deben recordar compilar antes de ejecutar pruebas web si la aplicación web ha cambiado. Hemos encontrado que esto no es un gran problema, especialmente si ejecuta pruebas web en CI.

Los datos son un gran reto. Por lo que puedo ver, debes elegir entre alternativas imperfectas. Así es como lo manejamos. Primero, debo explicar que estamos trabajando con una gran aplicación compleja de WebForms. También debo mencionar que el código de dominio no es adecuado para crear datos de prueba desde el proyecto de prueba.

Esto nos dejó con un par de opciones. Podríamos: (a) ejecutar scripts de configuración de datos bajo la compilación, o (b) crear todos los datos mediante pruebas web utilizando el sitio web real. El problema con la opción (a) es que las pruebas se combinan con scripts a un nivel de minuto. Me hace pensar en la sincronización de código de prueba web con T-SQL. Así que nos fuimos con (b).

Un beneficio de (b) es que su configuración también valida el comportamiento de la aplicación. El problema es ... el tiempo .

Idealmente, las pruebas deberían ser independientes, sin acoplamiento temporal (pueden ejecutarse en cualquier orden) y no compartir ningún contexto (por ejemplo, datos de prueba comunes). La forma común de manejar esto es configurar y eliminar datos con cada prueba. Después de un pensamiento cuidadoso, decidimos romper esta regla.

Utilizamos Gallio (MbUnit 3), que proporciona algunas características interesantes que respaldan nuestra estrategia. Primero, le permite especificar el orden de ejecución en el dispositivo y el nivel de prueba. Tenemos cuatro accesorios de "configuración" que están ordenados -4, -3, -2, -1. Estos se ejecutan en el orden especificado y antes de todos los dispositivos "no configurados", que de forma predeterminada tienen un orden de 0.

Nuestro proyecto de prueba web depende de la secuencia de comandos de compilación para una sola cosa: un único nombre de usuario / contraseña conocido. Este es un acoplamiento con el que puedo vivir. A medida que se ejecutan las pruebas de configuración, construyen un objeto de "contexto de datos" que contiene identificadores de datos (empresas, usuarios, proveedores, clientes, etc.) que luego se usan (pero nunca se cambian) en otros dispositivos. (Por identificadores, no me refiero necesariamente a claves. En la mayoría de los casos, nuestra interfaz de usuario web no expone claves únicas. Debemos navegar por la aplicación utilizando nombres u otros proxies para identificadores verdaderos. Más sobre esto a continuación).

Gallio también le permite especificar que una prueba o accesorio depende de otra prueba o accesorio. Cuando un precedente falla, el dependiente se salta. Esto reduce el mal del acoplamiento temporal al prevenir "fallas en cascada" que pueden generar mucha confusión.

La creación de datos de prueba de referencia una vez, en lugar de antes de cada prueba, acelera mucho las cosas. Sin embargo, las pruebas de configuración aún pueden tardar 10 minutos en ejecutarse. Cuando estoy trabajando en nuevas pruebas, quiero ejecutarlas y volverlas a ejecutar con frecuencia. Introduzca otra característica interesante de Gallio: Ambiente. El ambiente es una envoltura alrededor de DB4 que proporciona una forma muy simple de persistir objetos. Lo usamos para persistir el contexto de datos automáticamente. Por lo tanto, las pruebas de configuración solo deben ejecutarse una vez entre las reconstrucciones de la base de datos. Después de eso, puedes ejecutar cualquiera o todos los otros accesorios repetidamente.

Entonces, ¿qué pasa con la limpieza de datos de prueba? ¿No necesitamos partir de un estado conocido? Esta es una regla que hemos encontrado conveniente romper. Una estrategia que está funcionando para nosotros es usar valores aleatorios largos para cosas como el nombre de la empresa, el nombre de usuario, etc. Hemos encontrado que no es muy difícil realizar una prueba dentro de un "espacio de datos" lógico, de manera que no se vea afectado. en otros datos. Ciertamente, temo el día en que me pase horas persiguiendo una prueba de fallas fantasma solo para descubrir que es una colisión de datos. Es un intercambio que está funcionando para nosotros actualmente.

Estamos utilizando Watin. Me gusta bastante. Otra clave del éxito es algo a lo que Scott Bellware aludió. A medida que creamos pruebas, estamos construyendo un modelo abstracto de nuestra interfaz de usuario. Así que en lugar de esto:

browser.TextField("ctl0_tab2_newNote").TypeText("foo");

Verás esto en nuestras pruebas:

User.NotesTab.NewNote.TypeText("foo");

Este enfoque proporciona tres beneficios. Primero, nunca repetimos una cuerda mágica. Esto reduce grandemente la fragilidad. Segundo, las pruebas son mucho más fáciles de leer y entender. Por último, ocultamos la mayor parte del marco de Watin detrás de nuestras propias abstracciones. En el segundo ejemplo, solo TypeText es un método de Watin. Esto hará que sea más fácil cambiar a medida que cambia el marco.

Espero que esto ayude.

Estoy buscando sugerencias para mejorar el proceso de automatización de las pruebas funcionales de un sitio web. Esto es lo que he intentado en el pasado.

Solía ​​tener un proyecto de prueba usando WATIN . Usted escribe efectivamente lo que parecen "pruebas de unidad" y usa WATIN para automatizar un navegador para hacer clic en su sitio, etc.

Por supuesto, necesitas un sitio para estar corriendo. Así que realicé la prueba para copiar el código de mi proyecto web a un directorio local e inicié un servidor web que apunta a ese directorio antes de ejecutar cualquiera de las pruebas.

De esa manera, alguien nuevo podría simplemente obtener lo último de nuestro control de código fuente y ejecutar nuestro script de compilación, y ver cómo se ejecutan todas las pruebas. También podrían simplemente ejecutar todas las pruebas desde el IDE.

El problema que encontré fue que pasé mucho tiempo manteniendo el código para configurar el entorno de prueba más que las pruebas. Sin mencionar que tardó mucho tiempo en ejecutarse debido a todas esas copias. Además, necesitaba probar varios escenarios, incluida la instalación, lo que significa que necesitaba poder configurar la base de datos en varios estados iniciales.

Tenía curiosidad por lo que has hecho para automatizar las pruebas funcionales para resolver algunos de estos problemas y seguir siendo sencillo.

MÁS DETALLES Ya que la gente pidió más detalles, aquí está. Estoy ejecutando ASP.NET usando Visual Studio y Cassini (el servidor web incorporado). Mis pruebas de unidad se ejecutan en MbUnit (pero eso no es tan importante. Podría ser NUnit o XUnit.NET). Por lo general, tengo un marco de prueba de unidad separado que ejecuta todas mis pruebas WATIN. En la fase de ensamblaje, inicio el servidor web y copio todo el código de mi aplicación web localmente.

Me interesan las soluciones para cualquier plataforma, pero es posible que necesite más descripciones de lo que significa cada cosa. :)


¿Te refieres a comenzar automáticamente las pruebas después de que la construcción haya terminado? Podría escribir scripts automatizados para copiar los archivos de compilación a un IIS funcional mientras la compilación se realizó correctamente. Y luego inicie el BVT automatizado llamando a mstest.exe u otros métodos.

Puedes intentar con autoitx o con algún lenguaje funcional, como Python, ruby.


Actualmente estamos utilizando un proceso de compilación automatizado para nuestra aplicación mvc de asp.net.

Usamos las siguientes herramientas:

  • TeamCity
  • SVN
  • nUnidad
  • Selenio

Usamos un script msbuild que se ejecuta en un agente de compilación que puede ser cualquier cantidad de máquinas. El script msbuild obtiene la última versión de código de svn y la construye.

En caso de éxito, implementa los artefactos en una máquina / carpeta determinada y crea el sitio virtual en IIS.

Luego utilizamos tareas de contribución de MSBuild para ejecutar scripts de SQL para instalar la base de datos y cargar datos, también puede hacer una restauración.

En caso de éxito iniciamos las pruebas de nUnit. La configuración de la prueba garantiza que el selenio esté activo y en funcionamiento, y luego controla las pruebas de selenio de la misma manera que lo hace Watin. Selenium tiene un buen registrador para pruebas que pueden exportarse a c #.

Lo bueno de Selenium es que puedes manejar FF, Chorme e IE en lugar de estar restringido a IE, como fue el caso de Watin la última vez que lo vi. También puede usar Selenium para realizar pruebas de carga con Selenium Grid, por lo que puede reutilizar las mismas pruebas.

En caso de éxito, msbuild etiqueta la compilación en svn. TeamCity tiene un trabajo que se ejecuta durante la noche y que implementará la última etiqueta en un entorno de prueba listo para que los usuarios de negocios verifiquen el estado del proyecto a la mañana siguiente.

En una vida anterior teníamos nant y msbuild scripts para administrar completamente el entorno (instalación de java, selenio, etc.) sin embargo, esto lleva mucho tiempo, por lo que, como requisito previo, asumimos que cada agente de compilación tiene estos instalados. Con el tiempo vamos a incluir estas tareas.


Fue difícil, pero no imposible, construir una fase de prueba de integración en el proceso de construcción utilizando maven. Lo que sucedió fue esencialmente esto:

  • Ignore todas las pruebas JUNit en un directorio específico a menos que se inicie la fase de prueba de integración.
  • Agrega un perfil de maven para ejecutar las pruebas de integración.
  • Para la fase de prueba de preintegración -

  • Inicie Jetty ejecutando la aplicación golpeando una base de datos de prueba.

  • Inicia el servidor de selenio.
  • Ejecutar pruebas de integración de selenio en la fase de prueba de integración.
  • Detener el servidor de selenio
  • Deja de selenio

La dificultad en este paso fue realmente configurar el embarcadero: no pudimos lanzarlo solo desde una guerra, así que realmente tenemos que hacer que el embarcadero desempaquete la guerra, luego ejecutar el servidor, pero funciona, bueno, y está automatizado. todo lo que tiene que hacer es escribir mvn -PintegrationTest (que era nuestro nombre de perfil de prueba de integración) y desactivarlo.


Phil,

La automatización puede ser difícil de mantener, pero cuanto más use su automatización para la implementación, más podrá aprovecharla para la configuración de prueba (y viceversa).

Francamente, es más fácil evolucionar el código de automatización, factorizarlo y refactorizarlo en pequeñas unidades de funcionalidad específicas al usar una herramienta de compilación que no lo es.
simplemente manejando unidades de funcionalidad pre-factorizadas y compiladas estáticamente, como es el caso de NAnt y MSBuild. Esta es una de las razones por las que muchas personas que fueron usuarios relativamente tempranos de toole como NAnt se mudaron a Rake. La libertad de tratar el código de construcción como cualquier otro código (para evolucionar de forma continua su contenido y forma) es mayor con Rake. No terminas con la misma estasis en los artefactos de automatización tan fácil y rápidamente con Rake, y es mucho más fácil de escribir en Rake que NAnt o MSBuild.

Por lo tanto, parte de tu lucha está intrínsecamente relacionada con las herramientas. Para mantener su automatización sensible y mantenida, debe tener cuidado con las obstrucciones que imponen las herramientas de compilación estática como NAnt y MSBuild.

Le sugeriría que no conecte los ajustes de arranque del entorno de prueba de la carga de ensamblaje. Es un acoplamiento de adentro hacia afuera que solo sirve para una breve conveniencia. No hay nada malo (y, probablemente, todo correcto) con ir a la línea de comandos y ejecutar la tarea de compilación que configura el entorno antes de ejecutar pruebas desde el IDE o desde la línea de comandos, o desde una consola interactiva, como el C # REPL de El Proyecto Mono, o de IRB.

La configuración de datos de prueba es simplemente un dolor en el trasero a veces. Tiene que hacerse.

Necesitará una biblioteca a la que pueda llamar para crear y limpiar el estado de la base de datos. Puede hacer esas llamadas directamente desde su código de prueba, pero personalmente tiendo a evitar hacer esto porque hay más de un buen uso de datos de prueba o código de control de datos de muestra.

Conduzco todos los controles de datos de muestra de HTTP. Escribo controladores con acciones específicamente para controlar datos de muestra y emito GET contra esas acciones a través de Selenium. Los uso para crear y limpiar datos. Puedo componer los GET de estas acciones para crear escenarios comunes de datos de configuración, y puedo pasar valores específicos para los datos como parámetros de solicitud (o parámetros de formulario si es necesario).

Mantengo estos controladores en un área que normalmente llamo "test_support".

Mi automatización para implementar el sitio web no implementa el área de asistencia de prueba o sus rutas y mapeo. Como parte de mi automatización de verificación de implementación, me aseguro de que el código test_support no esté en la aplicación de producción.

También utilizo el código test_support para automatizar el control de todo el entorno: reemplazar los servicios por falsificaciones, desactivar los subsistemas para simular fallas y conmutaciones por error, activar o desactivar la autenticación y el control de acceso para las pruebas funcionales que no están relacionadas con estas facetas, etc.

Hay un gran valor secundario para controlar los datos de muestra o los datos de prueba de su aplicación web: al demostrar la aplicación, o al realizar pruebas exploratorias, puede crear los escenarios de datos que necesita simplemente emitiendo algunos enlaces contra las URL conocidas (o adivinables) en el área de test_support. Hacer un esfuerzo disciplinado para seguir rutas tranquilas y orientar los recursos aquí realmente valdrá la pena.

Hay mucho más en esta automatización funcional (que incluye pruebas, implementación, demostraciones, etc.) por lo que cuanto mejor diseñados estén estos recursos, mejor será el tiempo que tendrá para mantenerlos en el largo pasillo y más oportunidades tendrá para Aprovéchalos de manera imprevisible pero beneficiosa.

Por ejemplo, escribir un código de modelo de dominio sobre el modelo semántico de sus páginas web ayudará a crear un código de prueba mucho más comprensible y disminuirá la fragilidad. Si lo hace bien, puede usar esos mismos modelos con una variedad de controladores diferentes para poder aprovecharlos en pruebas de estrés y pruebas de carga, así como pruebas funcionales y usarlos desde la línea de comandos como herramientas de exploración. Por cierto, este tipo de cosas es más fácil de hacer cuando no estás obligado a los tipos de controladores como cuando usas un lenguaje estático. Hay una razón por la que muchos pensadores y creadores de pruebas principales trabajan en Ruby y por qué Watir está escrito en Ruby. La reutilización, la composición y la expresividad son mucho más fáciles de lograr en Ruby que en el código de prueba de C #. Pero esa es otra historia.

Vamos a ponernos al día y hablar más sobre el otro 90% de estas cosas :)


Utilizamos un Plasma en un proyecto. Emula un servidor web en proceso, solo apúntelo en la raíz de su proyecto de aplicación web.

Fue sorprendentemente estable, sin copiar archivos o iniciar un servidor fuera de proceso.

Aquí es cómo una prueba que usa Plasma nos parece ...

[Test] public void Can_log_in() { AspNetResponse response = WebApp.ProcessRequest("/Login.aspx"); AspNetForm form = response.GetForm(); form["UserName"] = User.UserName; form["Password"] = User.Password; AspNetResponse loggedIn = WebApp.ProcessRequest(Button.Click(form, "LoginUser")); Assert.IsTrue(loggedIn.IsRedirect()); AspNetResponse homePage = WebApp.ProcessRequest(loggedIn.GetRedirectUrl()); Assert.AreEqual(homePage.Status, 200); }

Todas las clases "AspNetResponse" y "AspNetForm" se incluyen con Plasma.