Определите, выполняется ли код как часть модульного теста - PullRequest
94 голосов
/ 02 июля 2010

У меня есть тестовый модуль (nUnit). На многих уровнях вниз по стеку вызовов метод завершится ошибкой, если он запущен через модульный тест.

В идеале вы бы использовали что-то вроде насмешки для настройки объекта, от которого зависит этот метод, но это сторонний код, и я не могу сделать это без большой работы.

Я не хочу настраивать nUnit конкретные методы - здесь слишком много уровней и плохой способ выполнения юнит-теста.

Вместо этого я хотел бы добавить что-то вроде этого глубоко в стек вызовов

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

Так есть идеи о том, как написать IsRunningInUnitTest?

P.S. Я полностью осознаю, что это не очень хороший дизайн, но я думаю лучше, чем альтернативы.

Ответы [ 16 ]

71 голосов
/ 02 июля 2010

Я делал это раньше - мне приходилось держать нос, пока я это делал, но я сделал это.Прагматизм побеждает догматизм каждый раз.Конечно, если - это - это хороший способ реорганизации, чтобы избежать его, это было бы здорово.

В основном у меня был класс "UnitTestDetector", который проверял, была ли загружена сборка фреймворка NUnitв текущем домене приложений.Это нужно было сделать только один раз, а затем кешировать результат.Уродливый, но простой и эффективный.

68 голосов
/ 02 июля 2010

Принимая идею Джона, это то, что я придумал -

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; }
    }
}

Труба сзади, мы все достаточно большие мальчики, чтобы понять, когда мы делаем что-то, чего мы, вероятно, не должны;)

53 голосов
/ 30 августа 2010

Адаптировано из ответа Райана. Этот предназначен для модульного тестирования MS.

Причина, по которой мне это нужно, в том, что я показываю MessageBox при ошибках. Но мои модульные тесты также тестируют код обработки ошибок, и я не хочу, чтобы при запуске модульных тестов появлялся MessageBox.

/// <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; }
}

А вот и юнит-тест для него:

    [TestMethod]
    public void IsInUnitTest()
    {
        Assert.IsTrue(UnitTestDetector.IsInUnitTest, 
            "Should detect that we are running inside a unit test."); // lol
    }
18 голосов
/ 16 июня 2014

Я использую такой же подход, как tallseth

Это основной код, который можно легко изменить, включив в него кэширование.Другой хорошей идеей было бы добавить сеттер к IsRunningInUnitTest и вызвать UnitTestDetector.IsRunningInUnitTest = false к главной точке входа ваших проектов, чтобы избежать выполнения кода.

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;
        }
    }
}
14 голосов
/ 20 мая 2015

Упрощая решение Райана, вы можете просто добавить следующее статическое свойство в любой класс:

    public static readonly bool IsRunningFromNUnit = 
        AppDomain.CurrentDomain.GetAssemblies().Any(
            a => a.FullName.ToLowerInvariant().StartsWith("nunit.framework"));
10 голосов
/ 05 июня 2013

Может быть полезно, проверка текущего ProcessName:

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
    }
}

И эту функцию также следует проверить с помощью unittest:

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

Ссылки:
Мэтью Уотсон в http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/11e68468-c95e-4c43-b02b-7045a52b407e/

9 голосов
/ 28 сентября 2012

В тестовом режиме Assembly.GetEntryAssembly() кажется null.

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

Обратите внимание, что если Assembly.GetEntryAssembly() равно null, Assembly.GetExecutingAssembly() нет.

Документация гласит: метод GetEntryAssembly может возвращать null, когда управляемая сборка была загружена из неуправляемого приложения.

8 голосов
/ 16 июля 2015

Где-то в тестируемом проекте:

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

Где-то в вашем проекте модульного тестирования:

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

Элегантно, нет.Но просто и быстро.AssemblyInitializer для MS Test.Я ожидаю, что другие тестовые структуры будут иметь эквиваленты.

3 голосов
/ 27 апреля 2011

Я использую это только для пропуска логики, которая отключает все TraceAppenders в log4net во время запуска, когда отладчик не подключен.Это позволяет модульным тестам регистрироваться в окне результатов Resharper даже при работе в режиме без отладки.

Метод, который использует эту функцию, вызывается либо при запуске приложения, либо при запуске тестового устройства.

Он похож на пост Райана, но использует LINQ, отбрасывает требование System.Reflection, не кэширует результат и является частным для предотвращения (случайного) неправильного использования.

    private static bool IsNUnitRunning()
    {
        return AppDomain.CurrentDomain.GetAssemblies().Any(assembly => assembly.FullName.ToLowerInvariant().StartsWith("nunit.framework"));
    }
1 голос
/ 26 ноября 2015

работает как шарм

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;
}

.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...