【问题标题】:Mockito thenReturn always null , Spring-Boot + Junit5 + MockitoMockito thenReturn 总是 null ,Spring-Boot + Junit5 + Mockito
【发布时间】:2021-12-30 14:47:08
【问题描述】:

我正在尝试实现 Mockito 来测试特定方法,但 .thenReturn(...) 似乎总是返回 null 对象,而不是我想要的:

我正在使用 mockito 2.22.0 和 Junit-5 以及 spring-boot 2.0.4.RELEASE

用户结果User=userService.save(userDto); 上面的行总是返回空指针异常。不知道为什么 resultUser 总是返回 null,

我的测试课

 @SpringBootTest
    public class UserServiceTests {
    
    @InjectMocks
    private UserService userService =new UserServiceImpl();
    
    @Mock
    private UserRepository userRepository;
    
    @Mock
    BCryptPasswordEncoder passwordEncoder;
    
    @BeforeEach
    void setUp() throws Exception{
        MockitoAnnotations.initMocks(this);
        
    }
    
    @DisplayName("Test saveRegistrationTest method making call to Repository")
    @Test
    public void saveRegistrationTest() {
        
        User user =new User();
        user.setFirstName("TestFN");
        user.setLastName("TestLN");
        user.setEmail("test@test.com");
        user.setPassword("7asdf7asdfi");
        
        User testUser =new User();
        testUser.setFirstName("TestFN");
        
        UserRegistrationDto userDto = new UserRegistrationDto();
        userDto.setFirstName("TestFN");
        
        when(userRepository.save(testUser )).thenReturn(user);
        
        **User resultUser=userService.save(userDto);**
        
        String firstName=(userService.save(userDto)).getFirstName();
        String lastName=(userService.save(userDto)).getLastName();
        String resultEmailFromRepo=(userService.save(userDto)).getEmail();
        String password=(userService.save(userDto)).getPassword();
        
        assertNotNull(user);
        assertEquals("TestLN", firstName);
        assertEquals("TestLN", lastName);
        assertEquals("test@test.com", resultEmailFromRepo);
        assertNotNull(password);
        assertEquals("7asdf7asdfi", password);
    }

用户实体

 @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String firstName;
    private String lastName;
    private String email;
    private String password;
    
    @OneToMany(cascade = CascadeType.ALL)
    private List<Todo> todoList = new ArrayList<>();

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(
            name = "users_roles",
            joinColumns = @JoinColumn(
                    name = "user_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(
                    name = "role_id", referencedColumnName = "id"))
    private Collection<Role> roles;

用户DTO

public class UserRegistrationDto {

    @NotEmpty
    private String firstName;

    @NotEmpty
    private String lastName;

    @NotEmpty
    private String password;

    @NotEmpty
    private String confirmPassword;

    @Email
    @NotEmpty
    private String email;

    @Email
    @NotEmpty
    private String confirmEmail;

    @AssertTrue
    private Boolean terms;

Userserviceimpl 类

   public User save(UserRegistrationDto registration){
        User user = new User();
        user.setFirstName(registration.getFirstName());
        user.setLastName(registration.getLastName());
        user.setEmail(registration.getEmail());
        user.setPassword(passwordEncoder.encode(registration.getPassword()));
        user.setRoles(Arrays.asList(new Role("TEST_USER")));
        user.setTodoList(null);
        return userRepository.save(user);
    }

【问题讨论】:

  • 不知道它是否能解决您的问题,但不应初始化 InjectMocks 的成员变量。此外,当 SpringBootTest 存在时,before each 方法不应该是必需的。

标签: java spring-boot mockito junit5


【解决方案1】:

不要

@InjectMocks
private UserService userService = new UserServiceImpl();

这个“对象”永远不会被spring管理!


最佳

@SpringBootTest
class UserServiceTest {
  @Autowired
  private UserService testee;

  @MockBean
  private UserRepository userRepoMock; // done!
  // ... many test methods, like: when(userRepoMock.xxx).thenYYY
  // testee.someMethod()
  // verify(userRepoMock...)
  // ...
}

服务的样子:

@Service // or some other "spring managed bean"
public class UserService {
  @Autowired
  private UserRepository userRepository;
 ...
}

正如约翰内斯所说:

@BeforeEach

在此设置中不需要(但无害??!)。


核心问题

当我们使用具体对象实例作为 mockito 的“参数匹配器”时:

when(userRepository.save(someObject)).thenReturn(someMock);

,我们应该确保,当(在测试期间):

userRepository(someOtherObject)

..被调用,

someObject.equals(someOtherObject)

...是true!("平等匹配器")

否则 mockito 可以/不会匹配该调用。

我们可以通过实现(自定义)equals(和hashCode)方法来解决:

// e.g. with lombok:
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
// ...
class UserRegistrationDto {
  @EqualsAndHashCode.Include
  String name;
}

EqualsAndHashCode(推荐,但要做好!(lombok小字,或手动!))


或者通过使用“更广泛的参数匹配器”,例如:

when(userRepository.save(any(UserRegistrationDto.class)).thenReturn(myMockResponse);

..甚至:

when(userRepository.save(any(/*java.lang.Object*/))...

ArgumentMatchers javadoc

【讨论】:

  • org.mockitomockito-core2.22.0test 没有找到 any() 方法
  • 我已经用更多信息更新了我的问题,请看看
  • 为我工作的最佳方法。所以我去了injectmocks
  • 在 import org.mockito.ArgumentMatchers 和 mockito 2.22.0 中找不到任何方法如果我使用最新版本 4.2.0,我的测试不起作用,
  • 我可以使用哪一个?最新版本
猜你喜欢
  • 2022-12-18
  • 1970-01-01
  • 2014-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-17
  • 1970-01-01
  • 2020-02-23
相关资源
最近更新 更多