【问题标题】:Mockito mock same method calls with different collection-argumentsMockito 使用不同的集合参数模拟相同的方法调用
【发布时间】:2020-11-28 03:38:54
【问题描述】:

我尝试使用不同的集合参数模拟相同的方法调用。

我的问题是我没有从 Mocked-Call 中获得正确的模拟答案作为输入。

测试类:

@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"))); // 
    }
}

控制器类:

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

我不知道为什么它不返回“a”。我试图将集合更改为字符串,但行为相同。

要执行哪些步骤才能获得以下行为?

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

我正在使用 Java Mockito "3.1" 和 Spring,但我认为 Mockito 是这里的重要信息。

【问题讨论】:

    标签: java testing mockito


    【解决方案1】:

    你的第二个电话 - Mockito.when(c.run(b)).thenReturn("b"); 否决了我们的第一次调用,因此 Mockito 将始终返回“b”。 如果您需要来自同一呼叫的多个答案,则可以使用 varags 变体:

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

    现在对控制器的 run 方法的第一次调用将返回“a”,所有后续调用都将返回“b”。您可以根据需要提供任意数量的返回结果,并且从那时起将重复最后一个作为答案。

    【讨论】:

      【解决方案2】:

      编写两个测试将显示您所期望的结果。 您正在向同一个控制器添加两个不同的结果,所以您只得到最后一个:Mockito.when(c.run(b)).thenReturn("b"); 普通的。您的 setUp() 中最后一个模拟的预期结果将保留在内存中。

      之前的回答是: 您可以使用 junit 和 mockito 之类的东西来测试您的 spring-web-mvc 应用程序。 看起来是这样的:

      @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"));                                                       
          }
      }
      

      举个例子:

      @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() )));
      }
      

      来自@see https://medium.com/backend-habit/integrate-junit-and-mockito-unit-testing-for-controller-layer-91bb4099c2a5的示例

      【讨论】:

      • 这与我的问题无关,或者我不明白。 --- 我的示例非常简单,请您帮我使用我的示例或任何几乎相同的示例,以便我了解如何解决我的问题?
      • 我认为您尝试获取一些参数,但这不是要走的路。 @见stackoverflow.com/a/17985015/390462
      • ThierryB 的初始评论在第一行解决了您的问题。您的测试代码告诉 Mockito 在控制器的 run 方法上返回“a”,然后告诉 Mockito 在控制器的 run 方法上返回“b”。因此,当最终调用控制器的 run 方法时,Mockito 将返回“b”,这是您最后告诉他要做的。您可以让 Mockito 像这样注册多个答案:when(c.run(anyCollection()).thenReturn("a", "b")。第一次调用将返回“a”,随后的调用将返回“b”。跨度>
      • @RudiVankeirsbilck 多个注册的答案/返回值将连续返回 - 很棒。这正是我需要的。我没有从 ThierryB 的解释中得到它,但无论如何感谢你们! ThierryB 或 RudiVankeirsbilck 你能否用最后的解释部分修改你的 Posted-Answer。然后我可以投票赞成您在 cmets 中做出的正确且易于理解的答案 :)
      猜你喜欢
      • 1970-01-01
      • 2011-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多