0

I have a Repository MyRepository which is a @Repository. This repository is used by one of my rest controllers. What I want to test is if authorization of my rest controller works properly, thus my tests use @WithUserDetails. I want to mock a call to MyRepository by following this tutorial. When I run my tests I get an exception saying:

org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);

Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
   Those methods *cannot* be stubbed/verified.
   Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.

Through some debugging I found out that my MockConfig#myRepository method is not being called.

src/main/java/com.example

MyRepository

@Repository
interface MyRepository extends CrudRepository<MyEntity, Long> {}

src/test/java/com.example

MockConfig

@Profile("test")
@Configuration
public class MockConfig
{
    @Bean
    @Primary
    public MyRepository myRepository()
    {
        return Mockito.mock(MyRepository.class);
    }
}

MyTestClass

@ActiveProfiles("test")
@AutoConfigureMockMvc
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class)
@TestExecutionListeners({
    DependencyInjectionTestExecutionListener.class
})
class MyTestClass
{
    @Autowired
    private MockMvc mvc;

    @Autowired
    private MyRepository myRepository;

    @Test
    @WithUserDetails("some_user")
    public void testWithCorrectPermissions()
    {
        long entityId = 1;

        MyEntity mockReturnValue = new MyEntity();
        Mockito.when(myRepository.findOne(entityId)).thenReturn(mockReturnValue);
        Mockito.when(myRepository.save(mockReturnValue)).thenReturn(mockReturnValue);

        this.mockMvc.perform(post("my/api/path")).andExpect(status().isOk());
    }
}
LimitX
  • 595
  • 3
  • 7
  • 23

2 Answers2

2

Try with the solution proposed in How to exclude a @Repository from component scan when using Spring Data Rest

Add the following annotation to your test class

@EnableJpaRepositories(excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {MyRepository.class})})
class MyTestClass
(...)
user2456718
  • 216
  • 1
  • 4
  • I don't quite understand why I have to exclude `MyRepository` from the component scan. Can you give me some context? – LimitX Apr 30 '18 at 10:11
0

If you want to mock the dependency(eg repository) for your testing class, I would suggest you to use MockitoJUnitRunner.class as SpringRunner.class will initialise the Spring application content, which will cause the testing to be slower and also more dependencies required depending on your project configuration.

So, for your MyTestClass

@RunWith(MockitoJUnitRunner.class)
public class MyTestClass{
    @Mock
    private MyRepository myRepository;

    private MyTest myTest;

    @Before
    public void setUp() throws Exception {
       myTest = new MyTest(myRepository);
    }

    @Test
    public void test(){
        ...
        when(myRepository.get(anyInt()).thenReturn(new MyEntity());
        ...
    }

There is some reference here.

If you insist to test using the current implementation, it might be that the MyRepository was scanned by the Spring Data and the bean was initialised by it. You might want to disable the component scanning as recommended by user2456718.

mengjiann
  • 275
  • 3
  • 12
  • Using MockitoJUnitRunner won't work for me as I need to login to my spring application thus my tests use `@WithUserDetails`. The purpose of my tests is to test authorization on my rest endpoints. I think I should've included this in my question – LimitX Apr 30 '18 at 09:59