Добавление фиктивного объекта в список шпионских программ Mockito

#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. Не ожидайте, что я снова поддержу ваш третий ответ 😉