День 2282. #Testing
Тестирование Характеристик
Большинство типов тестирования проверяют правильность. Мы тестируем код, чтобы увидеть, что он делает то, что мы хотим, чтобы он делал. Это предполагает, что мы знаем, что он должен делать. А что, если мы этого не знаем?
К сожалению, это бывает часто. Нужно вносить изменения в код, но мы недостаточно знаем о том, что он делает. Вот небольшой пример:
public class Parser
{
public static string FormatText(string text)
{
var result = new StringBuilder();
for (int n = 0; n < text.Length; ++n)
{
int c = text[n];
if (c == '<')
{
while (n < text.Length && text[n] != '/' && text[n] != '>')
n++;
if (n < text.Length && text[n] == '/')
n += 4;
else
n++;
}
if (n < text.Length)
result.Append(text[n]);
}
return result.ToString();
}
}
Что делает этот код? Кажется, удаляет HTML-теги из текста, но логика странная и, скорее всего, неправильная. Этот крошечный пример показывает, как сложно читать плохо написанный код. Мы можем использовать тестирование. Но вместо того, чтобы пытаться выяснить, является ли код правильным, мы можем попытаться охарактеризовать его поведение, чтобы понять, что он на самом деле делает. Начнем с простого теста. Создадим тест и назовём его «x». «X», потому что мы не знаем, что будет делать метод FormatText. И мы даже не зададим ожидаемого значения, т.к. на данный момент мы не знаем, каким будет поведение:
[TestMethod]
public void x()
{
Assert.AreEqual(null, Parser.FormatText("text"));
}
Тест упадёт, но мы хотя бы узнали, что метод выдаст в виде результата. Теперь мы можем поставить результат вместо ожидаемого значения и заставить тест проходить. А также зададим тесту имя, которое отражает наше понимание того, что делает код:
[TestMethod]
public void DoesNotChangePlainText()
{
Assert.AreEqual("text", Parser.FormatText("text"));
}
Мы не разобрались в коде, а пишем тесты. Какую ценность они могут иметь? Большую. Когда мы пишем тесты характеристик, мы накапливаем знания о том, что на самом деле делает код. Это особенно полезно, когда мы хотим его отрефакторить. Мы можем запустить наши тесты и сразу узнать, изменили ли мы поведение. Вот другой тест. Он проходит:
[TestMethod]
public void RemovesTextBetweenAngleBrackets()
{
Assert.AreEqual("", Parser.FormatText("<>"));
}
Показывает ли он ошибку в коде? Только контекст определит, является ли это правильным поведением. Когда вы пишете тесты характеристик, вы часто обнаруживаете поведение, о котором не знали. Т.е. цель тестирования характеристик — документировать фактическое поведение системы, а не проверять поведение, которое вы хотели бы, чтобы у системы было.
У вас было, что вы исправили ошибку, а пользователи стали жаловаться? Они не думали, что это ошибка, они думали, что это особенность системы. Когда система переходит в эксплуатацию, она в некотором смысле становится своей собственной спецификацией. Нам нужно знать, когда мы меняем существующее поведение, независимо от того, считаем мы его правильным или нет.
Мы можем рассматривать тесты характеристик как описания того, что у нас есть, а не как утверждения о правильности. Можно периодически пересматривать тесты, чтобы ужесточить их условия, когда мы решаем, каким должно быть поведение. Самое сложное — разорвать зависимости вокруг фрагмента кода, чтобы иметь возможность проверить его в тестовой среде. Как только вы это сделаете, останется только поинтересоваться, что будет делать код в определённых условиях и запустить тест, чтобы найти фактическое значение. Часто вы будете пересматривать названия тестов, поскольку будете больше понимать код, который проверяете. Начните с теста с именем «x».
Источник: https://michaelfeathers.silvrback.com/characterization-testing
>>Click here to continue<<