Sanjay
Sanjay

Reputation: 8945

How to mock Spring Data and unit test service

I'm trying to unit test a service method. The service methods calls a spring data repository method to fetch some data. I want to mock that repository call, and supply the data myself. How to do that? Following Spring Boot documentation, when I mock the repository and call the repository method directly in my test code, the mock is working. But when I call the service method, which in turn would call the repository method, mocking isn't working. Below is the sample code:

Service class:

@Service
public class PersonService {

    private final PersonRepository personRepository;

    @Autowired
    public PersonService(personRepository personRepository) {

        this.personRepository = personRepository;
    }

    public List<Person> findByName(String name) {
        return personRepository.findByName(name); // I'd like to mock this call
    }
}

Test class:

@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {

    // http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-testing-spring-boot-applications-mocking-beans
    @MockBean
    private PersonRepository personRepository;

    @Autowired
    private PersonService personService;

    private List<Person> people = new ArrayList<>();

    @Test
    public void contextLoads() throws Exception {

        people.add(new Person());
        people.add(new Person());

        given(this.personRepository.findByName("Sanjay Patel")).willReturn(people);

        assertTrue(personService.findByName("Sanjay Patel") == 2); // fails
    }
}

Upvotes: 5

Views: 18481

Answers (2)

derkoe
derkoe

Reputation: 6271

For Spring Data repositories you need to specifiy the bean name. Mocking via type doesn't seem to work because the repository is a dynamic proxy at runtime.

The default bean name for PersonRepository is "personRepository", so this should work:

@MockBean("personRepository")
private PersonRepository personRepository;

Here's the complete test:

@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {

    // http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-testing-spring-boot-applications-mocking-beans
    @MockBean("personRepository")
    private PersonRepository personRepository;

    @Autowired
    private PersonService personService;

    private List<Person> people = new ArrayList<>();

    @Test
    public void contextLoads() throws Exception {

        people.add(new Person());
        people.add(new Person());

        given(this.personRepository.findByName("Sanjay Patel")).willReturn(people);

        assertTrue(personService.findByName("Sanjay Patel") == 2); // fails
    }
}

Upvotes: 5

Alexandru Marina
Alexandru Marina

Reputation: 906

Probably the repository is marked with @MockedBean annotation. I do not know if Spring can auto wire by type if the repository is a mock. You can define the @Bean method and return Mockito.mock(X.class), this should work.

Not sure you need spring for unit testing a service method though. A lighter approach would be to use solely Mockito with its @InjectMocks annotation.

Upvotes: 0

Related Questions