Я використовую SpringBoot 1.5.9 і намагаюся зробити інтеграційне тестування. Дивно, що метод MongoRepository.save () оновлює об'єкт при виклику на макет MongoRepository.
У мене є лічильник класу
public class Counter {
public String id;
public int seq;
public void increaseSeq() {
this.seq += 1;
}
}
І його сховище
public interface CounterRepository extends MongoRepository<Counter, String>{
Counter findById(String id);
List<Counter> findAll();
}
І його служба
@Service
public class CounterService {
@Autowired private CounterRepository counterRepository;
public Counter findCounter(String id) {
return counterRepository.findById(id);
}
public int getSeqAndIncrease(String id) {
Counter counter = findCounter(id);
if (counter == null) {
return -1;
}
counter.increaseSeq();
counterRepository.save(counter);
return counter.getSeq();
}
}
Тепер, коли я роблю системну інтеграцію і намагаюся знущатисяcounterRepository, трапляється те, чого я не очікую. CounReRepository.findById () повертає об'єкт Counter, де поле "seq" збільшено. Чому? Чи впливає counterRepository.save () якимось чином на результат (counterRepository знущаються, отже, я вважаю, що save () не повинно мати жодного ефекту)?
@RunWith(SpringRunner.class)
@SpringBootTest
public class FlowServiceTest {
@MockBean private CounterRepository counterRepository;
@Autowired private CounterService counterService;
@Before
public void setUp() {
Mockito.when(counterRepository.save(any(Counter.class))).then(arg -> arg.getArgumentAt(0, Counter.class));
Mockito.when(counterRepository.findById("flow")).thenReturn(new Counter("flow", 10));
}
@Test
public void testSavingInDatabase() {
System.out.println(counterRepository.findById("flow"));
counterService.getSeqAndIncreaseSafe("flow");
System.out.println(counterRepository.findById("flow"));
counterService.getSeqAndIncreaseSafe("flow");
System.out.println(counterRepository.findById("flow"));
}
}
Друкується "10 11 12". Чому не друкується «10 10 10»?
Відповіді:
0 для відповіді № 1Проблема в цих рядках
counterRepository.save(counter);
return counter.getSeq();
Що ви повинні робити, це це
Counter saveCounter = counterRepository.save(counter);
return savedCounter.getSeq();
У методі getSeqAndIncrease ви не повертаєте послідовність збереженого об'єкта.
Роблячи це, ви робите свою фіктивну заяву для зберегти марно. Оскільки ви не використовуєте значення, повернене з макета.
0 для відповіді № 2
tl; dr - Повернутий об'єкт з mock ініціалізується лише один раз у mockito. Отже, я в основному отримував одне і те ж посилання кожного разу, і оскільки це посилання не є новим об’єктом, значення оновлюються.
Повна відповідь: При встановленні
Mockito.when(counterRepository.findById("flow")).thenReturn(new Counter("flow", 10));
, може здатися інтуїтивно зрозумілим повертати новий об’єкт кожного разу, але об’єкт повернення ініціалізується лише один раз, коли запускається тест, і буде повернутий при всіх наступних викликах.
Потім у своєму коді я це роблю
counter.increaseSeq();
що збільшує "seq" знайденого об'єкта (thisоб'єкт походить від Mockito). Потім при наступному виклику Mockito повертає перший ініціалізований об’єкт, який тим часом був оновлений; Mockito не повертає новий об'єкт, як може здатися.