- PVSM.RU - https://www.pvsm.ru -
Довольно часто при обсуждении средств статического анализа для C# проектов программисты пишут о том, что в этом нет необходимости, потому что с помощью юнит-тестирования они отлавливают большинство ошибок. Я решил проверить, насколько хорошо протестирован один из самых известных юнит-тест фреймворков — NUnit, и посмотреть найдёт ли там что-нибудь наш анализатор.
NUnit — это портированная с Java на C# популярная библиотека для юнит-тестирования .NET проектов. Исходный код открыт и доступен на сайте проекта http://www.nunit.org/ [1].
Стоит отметить, что JUnit — проект, с которого был портирован NUnit, создали такие известные программисты как Эрих Гамма — один из авторов книги о шаблонах объектно-ориентированного проектирования, и Кент Бек — создатель методологий разработки через тестирование и экстремального программирования. Я помню, как когда-то читал его книгу Test Driven Development By Example, где он рассказывает о разработке через тестирование на примере создания тестового фреймворка, аналогичного JUnit, следуя всем своим методологиям. То есть можно не сомневаться в том, что JUnit и NUnit разработаны в лучших традициях юнит-тестирования, о чём так же говорит цитата Кента Бека на сайте NUnit: "… великолепный пример идиоматического дизайна. Большинство тех, кто портировал xUnit просто переносили версию для Smalltalk или Java. То же самое сделали и мы с NUnit в первый раз. Эта новая версия NUnit является такой, какой она должна была быть, если бы была написана на C# с самого начала".
Я посмотрел исходники NUnit — там очень много тестов, ощущение такое, что протестировано всё что только можно. Учитывая отличный дизайн и тот факт, что NUnit используется тысячами разработчиков на протяжении многих лет, я думал, что PVS-Studio не найдёт в нём ни одной ошибки. Но нет, ошибка нашлась.
Сработала диагностика V3093 [2] о том, что иногда программисты вместо операторов && и || используют операторы & и |. Проблема может возникнуть в том случае, когда важно чтобы правая часть выражения не выполнялась при определённых условиях. Посмотрим, как эта ошибка выглядит в NUnit.
public class SubPathConstraint : PathConstraint
{
protected override bool Matches(string actual)
{
return actual != null &
IsSubPath(Canonicalize(expected), Canonicalize(actual));
}
}
public abstract class PathConstraint : StringConstraint
{
protected string Canonicalize(string path)
{
if (Path.DirectorySeparatorChar !=
Path.AltDirectorySeparatorChar)
path = path.Replace(Path.AltDirectorySeparatorChar,
Path.DirectorySeparatorChar);
....
}
}
Даже если в метод Matches в качестве параметра actual придёт значение null, то правая часть оператора & всё равно будет вычислена, а значит будет вызван метод Canonicalize. Если посмотреть его определение, то видно, что в нём значение параметра path уже не проверяется на null, а сразу у него зовётся метод Replace, где и возможен потенциальный NullReferenceException. Попробуем воспроизвести проблему. Для этого я написал простой юнит-тест:
[Test]
public void Test1()
{
Assert.That(@"C:Folder1Folder2", Is.SubPathOf(null));
}
Запускаем и смотрим результат:
Так и есть: NUnit упал с NullReferenceException. Даже в таком хорошо протестированном продукте как NUnit статический анализатор PVS-Studio смог найти реальную ошибку. Отмечу, что сделать это мне было не сложнее, чем написать юнит-тест — нужно выбрать из меню проверку проекта и проанализировать грид с результатами.
Юнит-тесты и статический анализ — это не исключающие, а дополняющие друг друга методики разработки программного обеспечения [1 [3]]. Скачайте [4] статический анализатор PVS-Studio и посмотрите не обнаружатся ли там ошибки, которые не были найдены юнит тестами.
Автор: PVS-Studio
Источник [6]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/c-2/174431
Ссылки в тексте:
[1] http://www.nunit.org/: http://www.nunit.org/
[2] V3093: http://www.viva64.com/ru/d/0494/
[3] 1: http://www.viva64.com/ru/a/0080/
[4] Скачайте: http://www.viva64.com/ru/pvs-studio-download/
[5] Об одной интересной ошибке в Lucene.Net: http://www.viva64.com/ru/b/0381/
[6] Источник: https://habrahabr.ru/post/307944/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.