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



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



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

710   12  

12 ответов:

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

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

общим шаблоном для написания модульных тестов является тестирование только общедоступных методов.

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

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

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

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

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

хотя я согласен с тем, что в центре внимания модульного тестирования должен быть открытый интерфейс, вы получаете гораздо более детальное представление о своем коде, если вы также тестируете частные методы. Платформа тестирования 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, если вы хотите протестировать private статический метод. Приведенный выше пример - это просто методы экземпляра.

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

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

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

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

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

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

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

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

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

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

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

#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

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

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

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

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

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

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

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

вы можете сделать свои методы защищенными внутренними, а затем использовать assembly: InternalVisibleTo("NAMESPACE") в ваше пространство имен тестирования.

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

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

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

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

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

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

    protected void SomeMethod2() {}
    [Test]
    public void SomeMethodTest() { SomeMethod2(); }
}

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

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

Я Java парень кстати, так что пакет visiblilty можно было бы назвать что-то совершенно другое в C#. Достаточно сказать, что это когда два класса должны быть в одном пространстве имен для доступа к этим методам.

Comments

    Ничего не найдено.