Для меня ключевое отличие заключается в том, что интеграционные тесты показывают, работает ли функция или нет, поскольку они подчеркивают код в сценарии, близком к реальности. Они вызывают один или несколько программных методов или функций и проверяют, работают ли они должным образом.
Напротив, модульный тест, тестирующий один метод, основан на (часто ошибочном) допущении, что остальная часть программного обеспечения работает правильно, потому что оно явно имитирует каждую зависимость.
Следовательно, когда модульный тест для метода, реализующего какую-либо функцию, имеет зеленый цвет, это не означает, что функция работает.
Скажем, у вас есть метод где-то вроде этого:
public SomeResults DoSomething(someInput) {
var someResult = [Do your job with someInput];
Log.TrackTheFactYouDidYourJob();
return someResults;
}
DoSomething
это очень важно для вашего клиента: это особенность, единственное, что имеет значение. Вот почему вы обычно пишете спецификацию Cucumber, утверждая это: хотите проверить и сообщить, работает ли функция или нет.
Feature: To be able to do something
In order to do something
As someone
I want the system to do this thing
Scenario: A sample one
Given this situation
When I do something
Then what I get is what I was expecting for
Нет сомнений: если тест пройден, вы можете утверждать, что предоставляете работающую функцию. Это то, что вы можете назвать бизнес-ценность .
Если вы хотите написать модульный тест для DoSomething
вас, вы должны притвориться (используя некоторые макеты), что остальные классы и методы работают (то есть, что все зависимости, которые использует метод, работают правильно) и утверждать, что ваш метод работает.
На практике вы делаете что-то вроде:
public SomeResults DoSomething(someInput) {
var someResult = [Do your job with someInput];
FakeAlwaysWorkingLog.TrackTheFactYouDidYourJob(); // Using a mock Log
return someResults;
}
Вы можете сделать это с помощью Dependency Injection, с помощью некоторого Factory Method или любой Mock Framework или просто путем расширения тестируемого класса.
Предположим, есть ошибка в Log.DoSomething()
. К счастью, спецификация Gherkin найдет его, и ваши сквозные тесты не пройдут.
Функция не будет работать, потому что Log
сломана, а не потому, что [Do your job with someInput]
не выполняет свою работу. И, кстати, [Do your job with someInput]
это единственная ответственность за этот метод.
Также предположим, что Log
используется в 100 других функциях, в 100 других методах 100 других классов.
Да, 100 функций не удастся. Но, к счастью, 100 сквозных тестов также дают сбой и выявляют проблему. И да: они говорят правду .
Это очень полезная информация: я знаю, что у меня сломан продукт. Это также очень запутанная информация: она ничего не говорит мне о том, где проблема. Это сообщает мне симптом, а не основную причину.
Тем не менее, DoSomething
юнит-тест зеленый, потому что он использует фальшивку Log
, созданную , чтобы никогда не ломаться. И да: это явно врет . Это сообщение сломанной функции работает. Чем это может быть полезно?
(Если DoSomething()
юнит тест не пройден, убедитесь, что [Do your job with someInput]
есть ошибки.)
Предположим, что это система со сломанным классом:
Одна ошибка нарушит несколько функций, а несколько интеграционных тестов не пройдут.
С другой стороны, та же самая ошибка сломает только один модульный тест.
Теперь сравните два сценария.
Эта же ошибка сломает только один юнит-тест.
- Все ваши функции, использующие сломанные
Log
, красные
- Все ваши юнит-тесты зеленые, только юнит-тест
Log
красный
На самом деле, модульные тесты для всех модулей, использующих неработающую функцию, имеют зеленый цвет, поскольку с помощью имитаций они удаляют зависимости. Другими словами, они бегут в идеальном, полностью вымышленном мире. И это единственный способ выявлять ошибки и искать их. Модульное тестирование означает издевательство. Если вы не издеваетесь, вы не юнит-тестирование.
Различия
Интеграционные тесты показывают, что не работает. Но они бесполезны в догадках, где может быть проблема.
Модульные тесты являются единственными тестами, которые говорят вам, где именно ошибка. Чтобы получить эту информацию, они должны запустить метод в смоделированной среде, где все другие зависимости должны работать правильно.
Вот почему я думаю, что ваше предложение «Или это просто юнит-тест, охватывающий 2 класса» как-то смещено. Модульный тест никогда не должен охватывать 2 класса.
Этот ответ в основном является кратким изложением того, что я написал здесь: модульные тесты лгут, поэтому я люблю их .