visual unitarias unit test studio pruebas interfaz ejemplos ejecución crear c# reflection nunit

c# - unitarias - Determine si el código se está ejecutando como parte de una prueba unitaria



pruebas unitarias interfaz (15)

Adaptado de la respuesta de Ryan. Este es para el marco de prueba de la unidad MS.

La razón por la que necesito esto es porque muestro un MessageBox sobre errores. Pero mis pruebas unitarias también prueban el código de manejo de errores, y no quiero que aparezca un MessageBox cuando se ejecutan pruebas unitarias.

/// <summary> /// Detects if we are running inside a unit test. /// </summary> public static class UnitTestDetector { static UnitTestDetector() { string testAssemblyName = "Microsoft.VisualStudio.QualityTools.UnitTestFramework"; UnitTestDetector.IsInUnitTest = AppDomain.CurrentDomain.GetAssemblies() .Any(a => a.FullName.StartsWith(testAssemblyName)); } public static bool IsInUnitTest { get; private set; } }

Y aquí hay una prueba de unidad para ello:

[TestMethod] public void IsInUnitTest() { Assert.IsTrue(UnitTestDetector.IsInUnitTest, "Should detect that we are running inside a unit test."); // lol }

Tengo una prueba unitaria (nUnit). Muchas capas en la pila de llamadas un método fallará si se está ejecutando a través de una prueba de unidad.

Lo ideal sería utilizar algo así como burlarse para configurar el objeto que depende de este método, pero este es un código de terceros y no puedo hacer eso sin mucho trabajo.

No quiero configurar métodos nUnit específicos: hay demasiados niveles aquí y es una manera pobre de hacer una prueba unitaria.

En cambio, lo que me gustaría hacer es agregar algo como esto en el fondo de la pila de llamadas

#IF DEBUG // Unit tests only included in debug build if (IsRunningInUnitTest) { // Do some setup to avoid error } #endif

Entonces, ¿alguna idea sobre cómo escribir IsRunningInUnitTest?

PD. Soy plenamente consciente de que este no es un gran diseño, pero creo que es mejor que las alternativas.


Application.Current es nulo cuando se ejecuta debajo del probador de la unidad. Al menos para mi aplicación WPF que usa el probador de MS Unit. Es una prueba fácil de hacer si es necesario. Además, algo a tener en cuenta al usar la aplicación. Actual en su código.


En algún lugar del proyecto que se está probando:

public static class Startup { public static bool IsRunningInUnitTest { get; set; } }

En algún lugar de su proyecto de prueba de unidad:

[TestClass] public static class AssemblyInitializer { [AssemblyInitialize] public static void Initialize(TestContext context) { Startup.IsRunningInUnitTest = true; } }

Elegante, no. Pero directo y rápido. AssemblyInitializer es para MS Test. Esperaría que otros frameworks de prueba tengan equivalentes.


En modo de prueba, Assembly.GetEntryAssembly () parece ser nulo.

#IF DEBUG // Unit tests only included in debug build if (Assembly.GetEntryAssembly() == null) { // Do some setup to avoid error } #endif

Tenga en cuenta que si Assembly.GetEntryAssembly () es nulo, Assembly.GetExecutingAssembly () no lo es.

La documentation dice: El método GetEntryAssembly puede devolver nulo cuando un ensamblado administrado se ha cargado desde una aplicación no administrada.


Funciona de maravilla

if (AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.FullName.ToLowerInvariant().StartsWith("nunit.framework")) != null) { fileName = @"C:/Users/blabla/xxx.txt"; } else { var sfd = new SaveFileDialog { ... }; var dialogResult = sfd.ShowDialog(); if (dialogResult != DialogResult.OK) return; fileName = sfd.FileName; }

.


Lo uso solo para omitir la lógica que deshabilita todos los TraceAppenders en log4net durante el inicio cuando no hay un depurador conectado. Esto permite que las pruebas unitarias se registren en la ventana de resultados de Resharper incluso cuando se ejecuta en modo no depuración.

El método que utiliza esta función se invoca al inicio de la aplicación o al iniciar un accesorio de prueba.

Es similar a la publicación de Ryan pero utiliza LINQ, omite el requisito de System.Reflection, no almacena en caché el resultado y es privado para evitar el uso indebido (accidental).

private static bool IsNUnitRunning() { return AppDomain.CurrentDomain.GetAssemblies().Any(assembly => assembly.FullName.ToLowerInvariant().StartsWith("nunit.framework")); }


No estaba contento de tener este problema recientemente. Lo resolví de una manera ligeramente diferente. En primer lugar, no estaba dispuesto a suponer que el marco nunit nunca se cargaría fuera de un entorno de prueba; Estaba particularmente preocupado por los desarrolladores que ejecutaban la aplicación en sus máquinas. Así que caminé la pila de llamadas en su lugar. En segundo lugar, pude suponer que el código de prueba nunca se ejecutaría contra los archivos binarios de lanzamiento, así que me aseguré de que este código no existiera en un sistema de lanzamiento.

internal abstract class TestModeDetector { internal abstract bool RunningInUnitTest(); internal static TestModeDetector GetInstance() { #if DEBUG return new DebugImplementation(); #else return new ReleaseImplementation(); #endif } private class ReleaseImplementation : TestModeDetector { internal override bool RunningInUnitTest() { return false; } } private class DebugImplementation : TestModeDetector { private Mode mode_; internal override bool RunningInUnitTest() { if (mode_ == Mode.Unknown) { mode_ = DetectMode(); } return mode_ == Mode.Test; } private Mode DetectMode() { return HasUnitTestInStack(new StackTrace()) ? Mode.Test : Mode.Regular; } private static bool HasUnitTestInStack(StackTrace callStack) { return GetStackFrames(callStack).SelectMany(stackFrame => stackFrame.GetMethod().GetCustomAttributes(false)).Any(NunitAttribute); } private static IEnumerable<StackFrame> GetStackFrames(StackTrace callStack) { return callStack.GetFrames() ?? new StackFrame[0]; } private static bool NunitAttribute(object attr) { var type = attr.GetType(); if (type.FullName != null) { return type.FullName.StartsWith("nunit.framework", StringComparison.OrdinalIgnoreCase); } return false; } private enum Mode { Unknown, Test, Regular }


Quizás útil, verificando ProcessName actual:

public static bool UnitTestMode { get { string processName = System.Diagnostics.Process.GetCurrentProcess().ProcessName; return processName == "VSTestHost" || processName.StartsWith("vstest.executionengine") //it can be vstest.executionengine.x86 or vstest.executionengine.x86.clr20 || processName.StartsWith("QTAgent"); //QTAgent32 or QTAgent32_35 } }

Y esta función también debe verificarse por unittest:

[TestClass] public class TestUnittestRunning { [TestMethod] public void UnitTestRunningTest() { Assert.IsTrue(MyTools.UnitTestMode); } }

Referencias
Matthew Watson en http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/11e68468-c95e-4c43-b02b-7045a52b407e/


Simplificando la solución de Ryan, puede agregar la siguiente propiedad estática a cualquier clase:

public static readonly bool IsRunningFromNUnit = AppDomain.CurrentDomain.GetAssemblies().Any( a => a.FullName.ToLowerInvariant().StartsWith("nunit.framework"));


También hay una solución realmente simple cuando estás probando una clase ...

Simplemente dale a la clase que estás probando una propiedad como esta:

// For testing purposes to avoid running certain code in unit tests. public bool thisIsUnitTest { get; set; }

Ahora su prueba de unidad puede establecer el valor booleano "thisIsUnitTest" en verdadero, por lo que en el código que desea omitir, agregue:

if (thisIsUnitTest) { return; }

Es más fácil y más rápido que inspeccionar los ensamblajes. Me recuerda a Ruby On Rails donde mirarías para ver si estás en el entorno de PRUEBA.


Tener una referencia a nunit framework no significa que la prueba se está ejecutando realmente. Por ejemplo, en Unity cuando activa las pruebas de modo de reproducción, las referencias de nunit se agregan al proyecto. Y cuando ejecuta un juego, las referencias existen, por lo que UnitTestDetector no funcionaría correctamente.

En lugar de verificar el ensamblado de nunit, podemos pedirle a nunit api que compruebe si el código está bajo la prueba de ejecución ahora o no.

using NUnit.Framework; // ... if (TestContext.CurrentContext != null) { // nunit test detected // Do some setup to avoid error }


Teniendo en cuenta que su código se ejecuta normalmente en el hilo principal (GUI) de una aplicación de formularios de Windows y desea que se comporte de manera diferente mientras se ejecuta en una prueba que puede verificar.

if (SynchronizationContext.Current == null) { // code running in a background thread or from within a unit test DoSomething(); } else { // code running in the main thread or any other thread where // a SynchronizationContext has been set with // SynchronizationContext.SetSynchronizationContext(synchronizationContext); DoSomethingAsync(); }

Estoy usando esto para el código que deseo fire and forgot en una aplicación de interfaz gráfica de usuario, pero en las pruebas de unidad podría necesitar el resultado calculado para una declaración y no quiero meterme con múltiples hilos en ejecución.

Funciona para MSTest. La ventaja es que mi código no necesita verificar el marco de prueba en sí y si realmente necesito el comportamiento asíncrono en una prueba determinada, puedo configurar mi propio SynchronizationContext.

Tenga en cuenta que este no es un método confiable para Determine if code is running as part of a unit test como lo solicita OP ya que el código podría estar ejecutándose dentro de un hilo, pero para ciertos escenarios podría ser una buena solución (también: si ya estoy ejecutándose desde un hilo de fondo, puede que no sea necesario iniciar uno nuevo).


Tomando la idea de Jon, esto es lo que se me ocurrió:

using System; using System.Reflection; /// <summary> /// Detect if we are running as part of a nUnit unit test. /// This is DIRTY and should only be used if absolutely necessary /// as its usually a sign of bad design. /// </summary> static class UnitTestDetector { private static bool _runningFromNUnit = false; static UnitTestDetector() { foreach (Assembly assem in AppDomain.CurrentDomain.GetAssemblies()) { // Can''t do something like this as it will load the nUnit assembly // if (assem == typeof(NUnit.Framework.Assert)) if (assem.FullName.ToLowerInvariant().StartsWith("nunit.framework")) { _runningFromNUnit = true; break; } } } public static bool IsRunningFromNUnit { get { return _runningFromNUnit; } } }

Conducir por la parte de atrás todos somos lo suficientemente grandes como para reconocer cuando estamos haciendo algo que probablemente no deberíamos;)


Ya he hecho esto antes: tuve que contener la nariz mientras lo hacía, pero lo hice. El pragmatismo vence al dogmatismo todo el tiempo. Por supuesto, si hay una buena manera de refactorizar para evitarlo, sería genial.

Básicamente, tuve una clase "UnitTestDetector" que verificaba si el ensamblado de la estructura NUnit se había cargado en el AppDomain actual. Solo necesitaba hacer esto una vez, luego almacenar en caché el resultado. Feo, pero simple y efectivo.


Yo uso un enfoque similar al de tallseth

Este es el código básico que podría modificarse fácilmente para incluir el almacenamiento en caché. Otra buena idea sería agregar un setter a IsRunningInUnitTest y llamar a UnitTestDetector.IsRunningInUnitTest = false al punto de entrada principal de su proyecto para evitar la ejecución del código.

public static class UnitTestDetector { public static readonly HashSet<string> UnitTestAttributes = new HashSet<string> { "Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute", "NUnit.Framework.TestFixtureAttribute", }; public static bool IsRunningInUnitTest { get { foreach (var f in new StackTrace().GetFrames()) if (f.GetMethod().DeclaringType.GetCustomAttributes(false).Any(x => UnitTestAttributes.Contains(x.GetType().FullName))) return true; return false; } } }