Властивості заглушки з приватними установками для тестів


10

У нас є об’єкт

public class MyObject{
    protected MyObject(){}

    public string Property1 {get;private set;}
    public string Property2 {get;private set;}
    public string Property3 {get;private set;}
    public string Property4 {get;private set;}
    public string Property5 {get;private set;}
    public string Property6 {get;private set;}
    public string Property7 {get;private set;}
    public string Property8 {get;private set;}
    public string Property9 {get;private set;}
    public string Property10 {get;private set;}
}

У нашому виробничому коді ми заповнюємо цей об'єкт за допомогою автоматичної машини. Він може отримати доступ до властивостей і встановити їх правильно.

Тепер, коли ми хочемо протестувати цей клас у майбутньому конвеєрі, неможливо заповнити властивості фіктивними значеннями (для перевірки).

Є кілька варіантів.

  • Спеціальні конструктори, щоб прийняти параметри, необхідні для тестів, і встановити властивості, в даний час потрібні 3 конструктори. Це не є чисто, оскільки конструктори не обслуговують жодної функціональності бізнесу.

  • Зробіть властивості віртуальними, щоб клас можна було заглушити. Але маркування властивостей віртуальними не дає ніякої цінності для бізнесу та забруднює мій клас.

  • Додайте конструктор об'єктів до класу для внутрішньої побудови об'єкта. Знову ніякої додаткової вартості бізнесу. Можливо, трохи чистіше, але все-таки багато невідповідного коду в об’єктах домену.

Тут є якісь пропозиції, поради чи альтернативні варіанти?

Відповіді:


8

У вас є ряд варіантів.

  • Вперед і використовуйте власні конструктори, віртуальні властивості або конструктор об'єктів. Обґрунтуванням цього є те, що об’єкт повинен стояти самостійно, а не залежати від якоїсь магії, як автомати. Клас, який абсолютно марний, якщо не відбувається якась магія, - це не дуже добре продуманий клас. "Ділова цінність" - не єдиний визначальний фактор хорошого дизайну.

  • Включіть автоматизатор в процес тестування. Деякі кажуть, що це вже не одиничне випробування. Не важливо. Блок тестування - не єдиний вид тестування.

  • Реалізуйте щось, що забезпечує функціональність автоматичного пристрою спеціально для тестування. Ви можете легко написати невелику утиліту, яка використовуватиме відображення для заповнення вашого об'єкта зі словника, що містить імена властивостей та значень.

Також погляньте на це запитання та відповідь: чи не хочете ви робити приватні речі внутрішніми / загальнодоступними для тестів чи використовувати якийсь хак, як PrivateObject?


3

Я не вагаюся використовувати рефлексію для подібних речей у тестах.

Мені не подобається робити речі віртуальними для глузування, оскільки це змінює код з неправильної причини.

Я не знаю автомати, але я згоден з @Mike, що включення його в тести може бути хорошою ідеєю. Тест на розрізнення тесту / інтеграції є не дуже цікавим. Звичайно, якщо набір тестів стає великим і повільним, вам потрібно буде відфільтрувати та класифікувати речі, щоб виконати лише розумний підмножина всіх тестів на найвищій частоті.

Зразок злому з використанням рефлексії, використовуючи nameof (), матиме кращі perf, але тоді ви втратите типи:

public static class TestExtensions
{
    public static void SetProperty<TSource, TProperty>(
        this TSource source,
        Expression<Func<TSource, TProperty>> prop,
        TProperty value)
    {
        var propertyInfo = (PropertyInfo)((MemberExpression)prop.Body).Member;
        propertyInfo.SetValue(source, value);
    }
}

0

З метою тестування одиниць використовуйте глузуючі рамки, такі як Microsoft Fakes, TypeMock та JustMock, яка забезпечує підтримку для глузування з приватних членів.

Перегляньте також Смоки (доступні пакети @nuget). Обмеження закусок - це не забезпечить доступ приватним членам. Але він має можливість знущатися над статичними та невіртуальними членами. Також він доступний безкоштовно.

Ще один найпростіший спосіб - це використання PrivateObject / PrivateType.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.