what unit tools test unit-testing language-agnostic windows-7

unit testing - tools - ¿Cómo terminar un programa cuando se bloquea?(lo cual debería fallar en una prueba unitaria en lugar de quedarse para siempre)



unit testing tools (3)

Nuestras pruebas de unidad generan procesos secundarios y, a veces, estos procesos secundarios se bloquean. Cuando esto sucede, aparece un cuadro de diálogo de Informes de Errores de Windows, y el proceso permanece activo hasta que se descarta manualmente. Esto, por supuesto, evita que las pruebas unitarias terminen.

¿Cómo puede esto ser evitado?

Aquí hay un diálogo de ejemplo en Win7 con la configuración habitual:

Si deshabilito la clave de registro AeDebug , la opción de depuración JIT desaparece:

Si desactivo la búsqueda de soluciones (lo único que parece tener control a través del panel de control), se ve así, pero aún aparece y aún detiene el programa hasta que el usuario presiona algo. WerAddExcludedApplication también tiene este efecto.


Intenta configurar

HKCU / Software / Microsoft / Windows / Informe de errores de Windows / DontShowUI

a 1. (También puede establecer la misma clave en HKLM, pero necesita privilegios de administrador para hacerlo).

Esto debería evitar que WER muestre cualquier UI.


La única solución es capturar todas las excepciones en un nivel muy alto (para cada subproceso) y finalizar la aplicación correctamente (o realizar otra acción).

Esta es la única forma de evitar que la excepción escape de su aplicación y active WER.

Adición:

Si la excepción es algo que no debe suceder, puede usar un AssertNoThrow (NUnit) o ​​similar en otro marco de prueba de unidad para encerrar el código que activa los procesos hijos. De esta forma también lo incluirías en tu informe de prueba de la Unidad. En mi opinión, esta es la solución más limpia posible que puedo pensar.

Adición2: como muestran los comentarios a continuación, me equivoqué: no siempre se pueden detectar las excepciones asincrónicas, depende de lo que el entorno permita. En .NET se evitan algunas excepciones, lo que hace que mi idea carezca de valor en este caso ...

Para .NET: Existen soluciones complicadas que implican el uso de AppDomains, lo que lleva a la descarga de un AppDomain en lugar de una falla de la aplicación completa. Demasiado...

http://www.bluebytesoftware.com/blog/PermaLink,guid,223970c3-e1cc-4b09-9d61-99e8c5fae470.aspx

http://www.develop.com/media/pdfs/developments_archive/AppDomains.pdf

EDITAR:

Finalmente lo tengo. Con .NET 4.0 Puede agregar el atributo HandleProcessCorruptedStateExceptions de System.Runtime.ExceptionServices al método que contiene el bloque try / catch. Esto realmente funcionó! Tal vez no recomendado, pero funciona.

using System; using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.ExceptionServices; namespace ExceptionCatching { public class Test { public void () { (); } public void CustomException() { throw new Exception(); } public unsafe void AccessViolation() { byte b = *(byte*)(8762765876); } } class Program { [HandleProcessCorruptedStateExceptions] static void Main(string[] args) { Test test = new Test(); try { //test.(); test.AccessViolation(); //test.CustomException(); } catch { Console.WriteLine("Caught."); } Console.WriteLine("End of program"); } } }


Un resumen de las respuestas de jdehaan y Eric Brown, además de esta pregunta (vea también esta pregunta ):

Nota: Estas soluciones también pueden afectar otros informes de errores, por ejemplo, no cargar un archivo DLL o abrir un archivo.

Opción 1: deshabilitar globalmente

Funciona globalmente en toda la cuenta de usuario o máquina, lo que puede ser a la vez un beneficio y un inconveniente.

Establezca [HKLM|HKCU]/Software/Microsoft/Windows/Windows Error Reporting/DontShowUI en 1. Más información: configuración de WER .

Opción 2: deshabilitar para la aplicación

Requiere la modificación del programa bloqueado, descrito en la documentación como la mejor práctica, no apto para una función de biblioteca.

Llamar a SetErrorMode : SetErrorMode(SetErrorMode(0) | SEM_NOGPFAULTERRORBOX); (o con SEM_FAILCRITICALERRORS ). Más información: deshabilitar el diálogo de bloqueo del programa (explica la extraña disposición de las llamadas).

Opción 2a: deshabilitar para una función :

Requiere la modificación del programa de bloqueo, requiere Windows 7/2008 R2 (aplicaciones de escritorio solamente) o superior, descrito en la documentación como preferido a SetErrorMode , adecuado para una función de biblioteca segura para subprocesos.

Llamar y restablecer SetThreadErrorMode :

DWORD OldThreadErrorMode = 0; SetThreadErrorMode(SEM_FAILCRITICALERRORS,& OldThreadErrorMode); … SetThreadErrorMode (z_OldThreadErrorMode, NULL);

Más información: ¿ no hay mucho disponible?

Opción 3: especificar un controlador

Requiere modificación al programa de bloqueo.

Use SetUnhandledExceptionFilter para configurar su propio manejador de excepciones estructuradas que simplemente salga, probablemente con informes y posiblemente un intento de limpieza.

Opción 4: captura como una excepción

Requiere modificación al programa de bloqueo. Para aplicaciones .NET solamente.

Envuelva todo el código en un bloque try / catch global. Especifique HandleProcessCorruptedStateExceptionsAttribute y posiblemente también SecurityCriticalAttribute en el método que captura las excepciones. Más información: Manejo de excepciones de estado dañadas

Nota : esto puede no detectar bloqueos causados ​​por los asistentes de depuración gestionados ; si es así, también deben estar deshabilitados en la aplicación.

Opción 5: Detener el proceso de informe

Funciona globalmente en toda la cuenta de usuario, pero solo por una duración controlada.

Mata el proceso de informe de errores de Windows cada vez que aparece:

var werKiller = new Thread(() => { while (true) { foreach (var proc in Process.GetProcessesByName("WerFault")) proc.Kill(); Thread.Sleep(3000); } }); werKiller.IsBackground = true; werKiller.Start();

Sin embargo, esto todavía no es completamente a prueba de balas, porque una aplicación de consola puede bloquearse a través de un mensaje de error diferente, aparentemente mostrado por una función interna llamada NtRaiseHardError :