Мы все были в точке, когда мы пишем тестовые примеры для нашего приложения и сталкиваемся с вызовом статического метода из стандартной библиотеки java. Оттуда все идет вниз. Mockito будет выдавать вам неоднозначные сообщения об ошибках. Обратите внимание, что нет общей причины, почему он выдает NullPointerException, и это во время насмешек.

Предпосылки

Этот пост предполагает некоторое знакомство с Unit testing с использованием таких фреймворков, как Mockito . Пример кода находится в Java 8 и требует понимания Functional Interfaces и Lambda functions в целом. Но это не то, что вам нужно для глубокого понимания. Если вы не знакомы с Java, не беспокойтесь, код достаточно прямолинейный и читабельный, так что вы сможете следовать ему.

А как насчет других фреймворков?

Это справедливый вопрос. А как насчет PowerMock? Пока я изучал эту тему, я наткнулся на PowerMock git repo, в котором прямо говорится:

Написание модульных тестов может быть трудным, и иногда хорошим дизайном приходится жертвовать единственной целью тестируемости.

Это помогает модульному тестированию этих методов, но я никогда не мог смириться с использованием всего фреймворка всего для нескольких применений здесь и там. Если вы предпочитаете вместо этого использовать фреймворк, то существует множество фреймворков, и самый популярный из них — PowerMock.

Пример

Для простоты сообщения в блоге предположим, что вы пишете метод, который получает rootDirectory и fileName. Метод должен вернуть содержимое файла. Теперь, если вы используете Java, вы должны использовать java.nio.file.Files API для вызова метода с именем walk() для перебора всех файлов в каталоге, а затем вы должны использовать метод readAllBytes() в java.nio.file.Files для чтения содержимого файла. Общий код будет выглядеть так

Проблема в том, что метод java.nio.file.Files.walk() и метод java.nio.file.Files.readAllBytes() являются static. Это вызывает проблему при модульном тестировании этого кода, поскольку мы не сможем mock получить ответы этих методов.

Функциональные интерфейсы в помощь

Что мы можем заметить, так это то, что мы используем два метода walk() и readAllBytes(), и нам совершенно не нужен какой-либо другой метод, который является частью класса java.nio.file.Files.

Интуиция состоит в том, чтобы создать два функциональных интерфейса, FileReader (читает все файлы в каталоге) и ContentReader (читает содержимое одного файла), каждый из которых выполняет одну часть процесса. Теперь вместо использования класса java.nio.file.Files мы внедряем два Functional Interfaces с помощью Constructor Injection.

Ниже приведен обновленный код.

Теперь вы можете просто использовать Mockito для имитации зависимостей с помощью @Mock, а затем использовать свободный синтаксис Mockito для имитации поведения.

when(mockedFReader.fetchFilesInDirectory(any())).thenReturn(sample);

Почему функциональные интерфейсы, а не класс Util?

Ответ — покрытие кода. Учитывая, что вы создаете новый класс и обертываете методы класса Files, вам все равно придется иметь дело с проблемами покрытия кода. Хотя, чтобы проверить свой класс FileOperator, вы можете имитировать зависимость, у вас все еще есть покрытие zero для вашего класса Util. Это хорошая практика или нет? основано на мнении.

Кроме того, использование функциональных интерфейсов упрощает внедрение зависимостей, особенно при использовании Dependency Injection framework, например Spring.

Вывод

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

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

Нравится эта статья? Пожалуйста, подпишитесь на @iam_Carrot в Твиттере. Может быть, нажмите кнопку аплодисментов 👏 несколько раз, чтобы показать свою поддержку ⬇⬇