0

I try to mock same method calls with different collection-arguments.

My problem is that im not getting the correct mocked-answer from Mocked-Call for the input.

Test-Class:

@ExtendWith(SpringExtension.class)
public class CollectionTest {

    @MockBean
    private Controller c;
    
    @BeforeEach
    public void init() {
        Collection<String> a = Mockito.anyCollection();
        a.add("a");
        Mockito.when(c.run(a)).thenReturn("a");
        
        Collection<String> b = Mockito.anyCollection();
        b.add("b");
        Mockito.when(c.run(b)).thenReturn("b");
    }

    @Test
    public void test() {
        assertEquals("a", c.run(Lists.newArrayList("a"))); // DOESNT'WORK!!! Returns "b" but should "a"
        assertEquals("b", c.run(Lists.newArrayList("b"))); // 
    }
}

Controller-Class:

@Service
public class Controller{
    public String run(Collection<String> c) {
        return "not-mocked";
    }   
}

I'v got no idea why it doesn't return "a". I tried to change the collection to string but same behaviour.

What are the Steps to do, to get the following behaviour?

@Test
public void test() {
    assertEquals("a", c.run(Lists.newArrayList("a"))); // should return "a"
    assertEquals("b", c.run(Lists.newArrayList("b"))); // should return "b"
}

Im using Java Mockito "3.1" and Spring, but I think Mockito is the important information here.

fo0
  • 186
  • 4
  • 12

2 Answers2

3

Your second call - Mockito.when(c.run(b)).thenReturn("b"); is overruling our first call so Mockito will therefore always return "b". If you need multiple answers from the same call, you can use the varags variant:

when(c.run(anyCollection())).thenReturn("a", "b");

Now the first call to the controller's run method will return "a" and all subsequent calls will return "b". You can provide as many return results as you want and the last one will be repeated from then on as the answer.

1

Write two tests will show you the results you are expecting. You are adding to the same Controller two different results so you get only the last one : Mockito.when(c.run(b)).thenReturn("b"); Normal. The last mocked expected result in your setUp() will stay in memory.

Previous answer was : You can use something like junit and mockito to test your spring-web-mvc application. It looks like that :

@WebMvcTest(controllers = UserController.class)
@ActiveProfiles("test")
class UserControllerTest {
   
    @Autowired                           
    private MockMvc mockMvc;  
                                                 
    @MockBean                           
    private UserService userService; 
                                               
    private List<User> userList;       
                                            
    @BeforeEach                           
    void setUp() {                               
       this.userList = new ArrayList<>();
       this.userList.add(new User(1L, "user1@gmail.com", "pwd1","User1"));
       this.userList.add(new User(2L, "user2@gmail.com", "pwd2","User2"));
       this.userList.add(new User(3L, "user3@gmail.com", "pwd3","User3"));                                                       
    }
}

And as an example :

@Test
void shouldFetchAllUsers() throws Exception {
    given(userService.findAllUsers()).willReturn(userList);
    this.mockMvc.perform(get("/api/users"))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.size()", is(userList.size() )));
}

Example from @see https://medium.com/backend-habit/integrate-junit-and-mockito-unit-testing-for-controller-layer-91bb4099c2a5

BendaThierry.com
  • 2,080
  • 1
  • 15
  • 17
  • This is not related to my question, or I don't get it. --- My Example is pretty simple, could you please help me to use my Example or any nearly identically one, that I can understand how my problem can be solved? – fo0 Aug 07 '20 at 22:54
  • I think you try to get some parameters, but is not the way to go. @see https://stackoverflow.com/a/17985015/390462 – BendaThierry.com Aug 07 '20 at 23:08
  • ThierryB's initial comment addresses your problem on the first line. Your test code tells Mockito to return "a" on the controller's run method and then tells Mockito to return "b" on the controller's run method. So when the controller's run method is eventually called, Mockito will return "b", what you told him to do last. You can have Mockito register multiple answers like this: when(c.run(anyCollection()).thenReturn("a", "b"). First call will return "a" and subsequent calls will return "b". – Rudi Vankeirsbilck Aug 08 '20 at 11:53
  • @RudiVankeirsbilck that multiple registered answers/return-values, will return in a row - is great. This is exactly what I need. I didnt get it from the explanation of ThierryB but anyway THANKS to you both!!! ThierryB or RudiVankeirsbilck could you maybe modify your Posted-Answer with the last explanation part. Then I can upvote the correct easy-to-understand answer you made here in the comments :) – fo0 Aug 08 '20 at 13:01