Как вы тестируете приватные методы с NUnit? - PullRequest
98 голосов
/ 30 октября 2008

Мне интересно, как правильно использовать NUnit. Сначала я создал отдельный Test-Project, который использует мой основной проект в качестве ссылки. Но в этом случае я не могу проверить частные методы. Я предположил, что мне нужно включить мой тест-код в мой основной код ?! - Это, кажется, не правильный способ сделать это. (Мне не нравится идея доставки кода с тестами в нем.)

Как вы тестируете приватные методы с NUnit?

Ответы [ 12 ]

68 голосов
/ 30 октября 2008

Как правило, модульное тестирование обращается к общедоступному интерфейсу класса, полагая, что реализация нематериальна, если результаты верны с точки зрения клиента.

Итак, NUnit не предоставляет никакого механизма для тестирования непубличных членов.

47 голосов
/ 27 января 2012

Хотя я согласен с тем, что основное внимание при модульном тестировании должно уделяться общедоступному интерфейсу, вы получите гораздо более детальное представление о своем коде, если будете тестировать и частные методы. Среда тестирования MS позволяет это с помощью PrivateObject и PrivateType, а NUnit - нет. Вместо этого я делаю:

private MethodInfo GetMethod(string methodName)
{
    if (string.IsNullOrWhiteSpace(methodName))
        Assert.Fail("methodName cannot be null or whitespace");

    var method = this.objectUnderTest.GetType()
        .GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);

    if (method == null)
        Assert.Fail(string.Format("{0} method not found", methodName));

    return method;
}

Этот способ означает, что вам не нужно ставить под угрозу инкапсуляцию в пользу тестируемости. Имейте в виду, что вам нужно изменить свои BindingFlags, если вы хотите проверить частные статические методы. Приведенный выше пример только для примера методов.

44 голосов
/ 30 октября 2008

Обычным шаблоном для написания юнит-тестов является тестирование только открытых методов.

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

Было бы неправильно обнародовать эти методы в классе, где они в настоящее время живут. Это нарушит контракт, который вы хотите иметь в этом классе.

Возможно, было бы правильно переместить их в класс помощников и сделать их там публичными. Этот класс может не отображаться вашим API.

Таким образом, тестовый код никогда не смешивается с вашим открытым кодом.

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

21 голосов
/ 30 октября 2008

Можно протестировать закрытые методы, объявив свою тестовую сборку дружественной сборкой целевой сборки, которую вы тестируете. Смотрите ссылку ниже для деталей:

http://msdn.microsoft.com/en-us/library/0tke9fxk.aspx

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

Как уже было сказано, вам действительно не нужно проверять частные методы. Вы более чем хотите, чтобы реорганизовать свой код в меньшие строительные блоки. Один совет, который может помочь вам, когда вы придете к рефакторингу, это попытаться подумать о домене, к которому относится ваша система, и подумать о «реальных» объектах, населяющих этот домен. Ваши объекты / классы в вашей системе должны иметь непосредственное отношение к реальному объекту, что позволит вам выделить точное поведение, которое должен содержать объект, а также ограничить ответственность объектов. Это будет означать, что вы проводите рефакторинг логически, а не просто чтобы сделать возможным тестирование определенного метода; Вы сможете проверить поведение объектов.

Если вы все еще чувствуете необходимость тестирования внутреннего, вы можете также подумать о том, чтобы при тестировании использовать макеты, так как вы хотите сосредоточиться на одном фрагменте кода. Насмешка - это то, где вы вводите в нее зависимости объектов, но внедренные объекты не являются «реальными» или производственными объектами. Это фиктивные объекты с жестко запрограммированным поведением, которые упрощают выявление поведенческих ошибок. Rhino.Mocks - это популярный бесплатный фреймворк, который по сути напишет объекты для вас. TypeMock.NET (коммерческий продукт с доступным выпуском для сообщества) является более мощной средой, которая может макетировать объекты CLR. Очень полезно для насмешки над классами SqlConnection / SqlCommand и Datatable, например, при тестировании приложения базы данных.

Надеемся, что этот ответ даст вам немного больше информации, чтобы проинформировать вас о модульном тестировании в целом и помочь вам получить лучшие результаты от модульного тестирования.

6 голосов
/ 16 июля 2013

Я за возможность тестировать приватные методы. Когда xUnit запускался, он предназначался для тестирования функциональности после написания кода. Для этого достаточно тестирования интерфейса.

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

4 голосов
/ 19 сентября 2014

Этот вопрос находится в продвинутом возрасте, но я подумал, что поделюсь своим способом сделать это.

По сути, у меня есть все мои классы модульных тестов в сборке, которые они тестируют в пространстве имен «UnitTest» ниже «по умолчанию» для этой сборки - каждый тестовый файл заключен в:

#if DEBUG

...test code...

#endif
Блок

, и все это означает, что а) он не распространяется в релизе и б) я могу использовать объявления уровня internal / Friend без прыжков с обручем.

Другая вещь, которую это предлагает, более уместная в этом вопросе, - это использование partial классов, которые можно использовать для создания прокси-сервера для тестирования закрытых методов, например, для тестирования чего-то вроде частного метода, который возвращает целочисленное значение:

public partial class TheClassBeingTested
{
    private int TheMethodToBeTested() { return -1; }
}

в основных классах сборки и в тестовом классе:

#if DEBUG

using NUnit.Framework;

public partial class TheClassBeingTested
{
    internal int NUnit_TheMethodToBeTested()
    {
        return TheMethodToBeTested();
    }
}

[TestFixture]
public class ClassTests
{
    [Test]
    public void TestMethod()
    {
        var tc = new TheClassBeingTested();
        Assert.That(tc.NUnit_TheMethodToBeTested(), Is.EqualTo(-1));
    }
}

#endif

Очевидно, вам нужно убедиться, что вы не используете этот метод при разработке, хотя сборка Release скоро укажет на непреднамеренный вызов этого метода, если вы это сделаете.

4 голосов
/ 30 октября 2008

Основной целью модульного тестирования является тестирование открытых методов класса. Эти публичные методы будут использовать эти закрытые методы. Модульное тестирование будет проверять поведение того, что является общедоступным.

3 голосов
/ 02 мая 2011

Извинения, если это не отвечает на вопрос, но такие решения, как использование отражений, выражений #if #endif или создание частных методов видимыми, не решают проблему. Может быть несколько причин не делать видимыми закрытые методы ... что если это рабочий код и команда ретроспективно пишет модульные тесты, например.

Для проекта, над которым я работаю, только MSTest (к сожалению), похоже, имеет способ, используя средства доступа, для модульного тестирования частных методов.

2 голосов
/ 30 октября 2008

Вы не тестируете частные функции. Есть способы использовать рефлексию, чтобы попасть в приватные методы и свойства. Но это не так просто, и я настоятельно не рекомендую эту практику.

Вы просто не должны проверять ничего, что не является общедоступным.

Если у вас есть какие-то внутренние методы и свойства, вам следует либо изменить их на общедоступные, либо отправлять свои тесты вместе с приложением (что я не вижу в качестве проблемы).

Если ваш клиент может запустить Test-Suite и увидеть, что код, который вы ввели, на самом деле «работает», я не вижу в этом проблемы (если вы не передаете свой IP через это ). В каждом выпуске я включаю отчеты о тестировании и отчеты о покрытии кода.

1 голос
/ 03 ноября 2016

В теории модульного тестирования должен быть проверен только контракт. т.е. только публичные члены класса. Но на практике разработчик обычно хочет проверить внутренних участников. - и это не плохо. Да, это противоречит теории, но на практике это иногда бывает полезно.

Таким образом, если вы действительно хотите проверить внутренних участников, вы можете использовать один из следующих подходов:

  1. Сделайте вашего участника публичным. Во многих книгах авторы предлагают это подход как простой
  2. Вы можете сделать своих членов внутренними и добавить InternalVisibleTo к assebly
  3. Вы можете сделать членов класса защищенными и наследовать ваш тестовый класс от вашего тестируемого класса.

Пример кода (псевдокод):

public class SomeClass
{
    protected int SomeMethod() {}
}
[TestFixture]
public class TestClass : SomeClass{

    protected void SomeMethod2() {}
    [Test]
    public void SomeMethodTest() { SomeMethod2(); }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...