#java #unit-testing #junit #mockito
#java #модульное тестирование #junit #mockito
Вопрос:
Не может Spy
ли объект списка Mockito содержать другие добавленные к нему фиктивные объекты? Есть ли альтернативы, кроме создания реальных объектов?
У меня есть объект списка шпионов
Class TestableClassTest {
@InjectMocks
TestableClass myClassUnderTest;
@Mock
MyService myService
@Spy
List<MyBusinessClass> myBusinessClasses;
@Mock
MyBusinessClass myBusinessClass1;
@Mock
MyBusinessClass myBusinessClass2;
ResponseEntity resu<
@Rule
MockitoRule rule = MockitoJunit.rule();
@Before
public void setup()
{
myBusinessClasses.add(myBusinessClass1);
myBusinessClasses.add(myBusinessClass2);
when(myService.get()).thenReturn(myBusinessClasses);
result = myClassUnderTest.testThisMethod();
}
@Test
public void resultIsReceivedWithNoException()
{ Assert.assertNotNull(result);}
}
Но при этом возвращается исключение nullpointer
List<MyBusinessClass> list = someService.get(); MyBusinessClass
myBusinessClass = list.get(0);// this is null
Это работает, только если я создаю реальный объект myBusinessClass1
и myBusinessClass2
из MyBusinessClass
, а затем добавляю его в spy()
список. Я имею в виду, что я больше не получаю null, если я создаю объекты с MyBusinessClass myBusinessClass1 = new MyBusinessClass()
помощью, а затем добавляю их в список.
Редактировать: Итак, мои вопросы при модульном тестировании класса, где мы возвращаем список из get()
метода издевательского класса. Как я могу добавить в этот список некоторые реальные конкретные данные, чтобы я Class Method which I am testing
мог работать с этими данными, а затем я могу проверить, что мой метод корректно работает с данными.
Комментарии:
1.—
myBusinessClass1
«Это работает, только если я создаю конкретные классы дляmyBusinessClass2
и « Это явно неправильное наблюдение, поскольку показанный вами код не вызывает никакого метода для этих двух объектов.
Ответ №1:
Итак, мои вопросы при модульном тестировании класса, в котором мы возвращаем список из метода get() издевательского класса. Как я могу добавить в этот список некоторые реальные конкретные данные, чтобы мой метод класса, который я тестирую, мог работать с этими данными, а затем я могу проверить, что мой метод корректно работает с данными.
Учитывая, что MyBusinessClass
это реальная зависимость, обеспечивающая некоторую бизнес-логику, которая имеет свои собственные unittests, подход будет выглядеть следующим образом:
@Mock
MyService myService
List<MyBusinessClass> myBusinessClasses = new ArrayList<>();
@Mock
MyBusinessClass myBusinessClass1;
@Mock
MyBusinessClass myBusinessClass2;
@Before
public void setup()
{
myBusinessClasses.add(myBusinessClass1);
myBusinessClasses.add(myBusinessClass2);
when(myService.get()).thenReturn(myBusinessClasses);
}
@Test
public void callSomeMethodOnReturnedEntries(){
new CodeUnderTest(myService).publicInterfaceMethod();
verify(myBusinessClass1).expectedMethodCall();
verify(myBusinessClass2).expectedMethodCall();
}
Комментарии:
1. Спасибо. В моем предыдущем руководстве говорилось, что ничто не должно быть реальным объектом, но я думаю, что для объектов-контейнеров мы не должны издеваться над ними, верно?
2. @Dexters существует аргумент, должны ли мы что-либо издеваться или вообще ничего . Я предпочитаю подход anything , за исключением DTO и коллекций.
3. @GhostCat просто копирует и вставляет, низко висящие фрукты … ; o)
Ответ №2:
Это здесь:
@Spy
List<MyBusinessClass> myBusinessClasses;
На самом деле это не имеет никакого смысла. Шпион позволяет частично имитировать «шпионский» объект. Таким образом, вы могли бы иногда вызывать «настоящие» методы и предотвращать вызов других. Смотрите Здесь руководство, почему / как использовать шпион Mockito.
Но вы действительно не должны этого делать для объектов списка. Списки — это просто контейнеры. Когда у вас есть модульный тест, и вам нужно управлять экземпляром списка, вы делаете это, просто помещая необходимые объекты в этот список. Вам не нужен список mocked или spy. Вы просто создаете некоторый экземпляр списка и помещаете в него объекты, которые вы хотите, чтобы он содержал.
Итак, суть в том, что вы должны убедиться, как вы можете вернуть someService.get();
этот список с известным содержимым. Но мы не можем помочь с этой частью, пока вы не обновите свой вопрос соответствующим образом.
Ответ №3:
В моем предыдущем руководстве говорилось, что ничто не должно быть реальным объектом
В этом случае вы также будете издеваться (а не шпионить) над коллекцией за счет необходимости указывать ее простое поведение:
@Mock
MyService myService
@Mock
List<MyBusinessClass> myBusinessClasses;
@Mock
MyBusinessClass myBusinessClass1;
@Mock
MyBusinessClass myBusinessClass2;
@Before
public void setup()
{
myBusinessClasses.add(myBusinessClass1);
myBusinessClasses.add(myBusinessClass2);
when(myBusinessClasses.size()).thenReturn(2);
when(myBusinessClasses.get(0)).thenReturn(myBusinessClass1);
when(myBusinessClasses.get(1)).thenReturn(myBusinessClass2);
when(myService.get()).thenReturn(myBusinessClasses);
}
@Test
public void callSomeMethodOnReturnedEntries(){
new CodeUnderTest(myService).publicInterfaceMethod();
verify(myBusinessClass1).expectedMethodCall();
verify(myBusinessClass2).expectedMethodCall();
}
Я бы для себя назвал это излишеством.
не по теме
Это сделало бы плохой unittest, поскольку он зависит от некоторых деталей реализации:
от того, как ваш производственный код обращается к элементам в этом списке.
Если вы решите изменить эту деталь реализации, скажем, с помощью итератора списка или API потока коллекций, вам придется изменить этот unittest, чтобы принять новую реализацию.
По-настоящему плохо здесь то, что в этом случае этот тест не может доказать, что ваш рефакторинг изменения доступа к элементу не изменил желаемое поведение бизнеса.
Комментарии:
1. вау! Раньше я делал это именно для того, чтобы получить пропуск на проверку кода! И я действительно чувствовал себя излишним, и именно поэтому начал изучать использование spy 🙂
2. Не ожидайте, что я снова поддержу ваш третий ответ 😉