Pull to refresh

Comments 6

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

Скорее наоборот.

Возможность доступа к приватным полям и методам, крайне упрощает тестирование.

Есть, конечно, BlackBox тестирование, но его польза сильно ограничена.

Про минусы такого подхода также было сказано - хрупкость тестов. Стоит взвесить плюсы и минусы.

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

public class Subject
{
    private int value;
  
    public Subject(int value) => this.value = value;
}

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

public class Subject
{
    private int value;
  
    // exposing a private field to subclasses
    // is less harm than making it public
    protected int Value => value;
  
    public Subject(int value) => this.value = value;
}

public class TestableSubject : Subject
{
    // transitively grant client code (i.e.test)
    // access to the private field
    public new int Value => base.Value;
    
    public TestableSubject(int value) : base(value) { }
}

И тестируем спокойно:

[Test]
public void NormalTest()
{
    // Arrange
    int value = 42;

    // Act
    var sut = new TestableSubject(value);

    // Assert
    Assert.AreEqual(value, sut.Value);
}

Правда, такой фокус потом любой пользователь библиотеки повторить сможет.

У .NET есть InternalsVisibleToAttribute и вообще рефлексия:

public class Subject
{
    private int value;

    public Subject(int value) => this.value = value;
}

public class TestableSubject : Subject
{
    public int Value => (int)typeof(Subject).GetField("value",
        BindingFlags.NonPublic | BindingFlags.Instance)
        .GetValue(this);

    public TestableSubject(int value) : base(value) { }
}

Еще для .NET есть штуки вроде этой, которые могут патчить код после компиляции. Клиенты получают оригинальную библиотеку, а тесты патченную с открытым доступом к чему угодно. Думаю, для других платформ аналоги тоже есть.

Хрупкость - понятие относительное.

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

В этом случае, как таковой хрупкости нет.

Тут чситый закон Мерфи србатывает: если вытащить что-то в публичный API, то его сразу же подхватять и потащат по своему коду и нельзя будет договорится не использовать его. И это будет не тот случай, когда нужно изменить API, потому что это нужно людям. Люди странные и дуамют странно. А гряный API это как детей ругатся учить - тебя же потом и обругают.

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

Т.е. полезно для тестов иметь доступ к действительно приватным методам и полям.

Sign up to leave a comment.