1

I am writing a SpringBoot integration test where I need to be able to mock interactions with external services while at the same time using some real objects (like interfaces which extend JPARepository) to interface with my database.

So let's say my class under test is as follows,

@Service
class MyService {
     @Autowired
     MyRepository myRepository; // This is the JPARepository which I want to use the real thing

     @Autowired
     OtherService otherService; // This one I really want to mock

     public class myMethod() {
         //Code which composes anEntity
         //anEntity is not null
         MyEntity myEntity = myRepository.save(anEntity); //after save myEntity is null
         myEntity.getId(); // this will throw an NPE
     }
}

Now here is my test class,

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
class MyServiceTest {
    @InjectMocks
    MyService service;

    @Spy
    @Autowired
    MyRepository myRepository;

    @Mock
    OtherService otherService

    public void testMyMethod() {
        myService.myMethod();
    }
}

Basically injecting of mocks and spys all seems to be going fine but for some reason when I call save on MyRepository it returns a null object instead of an entity.

Is there any way to workaround this issue?

Moiz Raja
  • 5,612
  • 6
  • 40
  • 52

1 Answers1

1

Instead of above construct, just use Spring Boot native annotation @SpyBean Yo ualso need to autowire testing class, which is in this case MyService.

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
class MyServiceTest {
    @SpyBean
    MyRepository myRepository;

    @Autowired
    OtherService otherService

    public void testMyMethod() {
        myService.myMethod();
    }
}
luboskrnac
  • 23,973
  • 10
  • 81
  • 92
  • [this stack question](https://stackoverflow.com/questions/54709589/spring-spybean-vs-mockitospy) provides more info about differences between Spy and SpyBean – aurelia Sep 01 '21 at 05:02