Ключевым отличием для меня является то, что интеграционные тесты показывают, работает ли функция или нет, поскольку они подчеркивают код в сценарии, близком к реальности. Они вызывают один или несколько программных методов или функций и проверяют, работают ли они должным образом.
Напротив, Модульный тест , проверяющий один метод, основан на (часто ошибочном) допущении, что остальная часть программного обеспечения работает правильно, поскольку оно явно проверяет каждую зависимость.
Следовательно, когда модульный тест для метода, реализующего некоторую функцию, имеет зеленый цвет, он не означает, что функция работает.
Скажем, у вас есть метод где-то вроде этого:
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 класса.
Этот ответ в основном является кратким изложением того, что я написал здесь: Модульные тесты лгут, поэтому я люблю их .