Я новичок в разработке и, в частности, в модульных тестах. Я предполагаю, что мое требование довольно простое, но я очень хочу узнать мнение других по этому поводу.
Предположим, у меня есть два таких класса -
public class First {
Second second ;
public First(){
second = new Second();
}
public String doSecond(){
return second.doSecond();
}
}
class Second {
public String doSecond(){
return "Do Something";
}
}
Скажем, я пишу модульный тест для First.doSecond()
метода тестирования . Однако, предположим, я хочу, чтобы Second.doSecond()
класс Mock был таким. Для этого я использую Mockito.
public void testFirst(){
Second sec = mock(Second.class);
when(sec.doSecond()).thenReturn("Stubbed Second");
First first = new First();
assertEquals("Stubbed Second", first.doSecond());
}
Я вижу, что насмешка не действует, а утверждение не выполняется. Нет возможности издеваться над переменными-членами класса, который я хочу протестировать. ?
Это невозможно, если вы не можете изменить свой код. Но мне нравится внедрение зависимостей, и Mockito его поддерживает:
Ваш тест:
Это очень красиво и просто.
источник
Если вы внимательно посмотрите на свой код, вы увидите, что
second
свойство в вашем тесте по-прежнему является экземпляромSecond
, а не макетом (вы не передаете макетfirst
в свой код).Самый простой способ будет создать сеттер для
second
вFirst
классе и передать ему издеваться явно.Как это:
Другой вариант - передать
Second
экземпляр какFirst
параметр конструктора.Если вы не можете изменить код, я думаю, единственный вариант - использовать отражение:
Но вы, вероятно, можете, поскольку редко можно проводить тесты на коде, который вы не контролируете (хотя можно представить сценарий, в котором вам нужно протестировать внешнюю библиотеку, потому что автор этого не сделал :))
источник
@Mock
и аннотируйте First с помощью@InjectMocks
и создайте экземпляр First в инициализаторе. Mockito автоматически сделает все возможное, чтобы найти место для внедрения второго макета в первый экземпляр, включая установку частных полей, соответствующих типу.@Mock
было примерно в 1.5 (может и раньше, не уверен). Введены 1.8.3,@InjectMocks
а также@Spy
и@Captor
.Если вы не можете изменить переменную-член, то другой способ - использовать powerMockit и вызвать
Теперь проблема в том, что ЛЮБОЙ вызов new Second вернет тот же фиктивный экземпляр. Но в вашем простом случае это сработает.
источник
У меня была такая же проблема, когда частное значение не было установлено, потому что Mockito не вызывает суперконструкторы. Вот как я дополняю насмешку отражением.
Во-первых, я создал класс TestUtils, который содержит множество полезных утилит, включая эти методы отражения. Реализовать доступ к отражению каждый раз непросто. Я создал эти методы для тестирования кода в проектах, в которых по той или иной причине не было макета пакета, и меня не пригласили включить его.
Затем я могу протестировать класс с такой частной переменной. Это полезно для имитации глубоких деревьев классов, которые вы тоже не контролируете.
Я изменил свой код из моего реального проекта здесь, на странице. Может быть проблема с компиляцией или две. Думаю, вы поняли общую идею. Не стесняйтесь брать код и использовать его, если он вам пригодится.
источник
Многие другие уже советовали вам переосмыслить свой код, чтобы сделать его более тестируемым - хороший совет и обычно проще, чем то, что я собираюсь предложить.
Если вы не можете изменить код, чтобы сделать его более тестируемым, PowerMock: https://code.google.com/p/powermock/
PowerMock расширяет Mockito (поэтому вам не нужно изучать новую фиктивную структуру), предоставляя дополнительные функции. Это включает возможность иметь конструктор, возвращающий макет. Мощный, но немного сложный - поэтому используйте его с умом.
Вы используете другой Mock-раннер. И вам нужно подготовить класс, который будет вызывать конструктор. (Обратите внимание, что это обычная проблема - подготовьте класс, который вызывает конструктор, а не созданный класс)
Затем в вашей тестовой настройке вы можете использовать метод whenNew, чтобы конструктор возвращал макет
источник
Да, это можно сделать, как показывает следующий тест (написанный с помощью API-интерфейса JMockit, который я разрабатываю):
Однако с Mockito такой тест не может быть написан. Это связано с тем, как макетирование реализовано в Mockito, где создается подкласс класса, который будет издеваться; только экземпляры этого «фиктивного» подкласса могут иметь фиктивное поведение, поэтому вам нужно, чтобы тестируемый код использовал их вместо любого другого экземпляра.
источник
Если вам нужна альтернатива ReflectionTestUtils из Spring в mockito, используйте
источник