AssertEquals 为两个相同的对象返回 false
AssertEquals returning false for two objects which are same
我有两个内容相同的用户定义对象。但是 assertsEquals 反过来等于方法 returns false 对于那些对象。
这里是堆栈跟踪,其中也包含对象的 toString 内容。
java.lang.AssertionError: expected: com.xyz.test.model.VerificationToken<VerificationToken(id=null, token=, user=User(userId=null, username=null, email=null, password=null, isActive=0, roles=null, imageLocation=null, enabled=false, isAccountNonLocked=true), expiryDate=Sat Dec 22 22:48:49 IST 2018)> but was: com.xyz.test.model.VerificationToken<VerificationToken(id=null, token=, user=User(userId=null, username=null, email=null, password=null, isActive=0, roles=null, imageLocation=null, enabled=false, isAccountNonLocked=true), expiryDate=Sat Dec 22 22:48:49 IST 2018)>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:118)
at org.junit.Assert.assertEquals(Assert.java:144)
at ....
我对应的class如下。这有生成 Equals 方法的 lombak 的 @data 注释。
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class VerificationToken implements Serializable{
/**
*
*/
private static final long serialVersionUID = 8788934708305097680L;
private static final int EXPIRATION = 60 * 24;
@Id
private Long id;
private String token;
private User user;
private Date expiryDate;
public Date calculateExpiryDate(int expiryTimeInMinutes) {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.MINUTE, expiryTimeInMinutes);
return new Date(cal.getTime().getTime());
}
}
我的用户class如下。这也有 @Data 注释,它生成 Equals 方法
@Entity
@Table(name = "user")
@Data
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = -6480423780555564185L;
@Id
private Integer userId;
private String username;
private String email;
@JsonIgnore
private String password;
private int isActive;
private Set<Role> roles;
private String imageLocation;
private boolean enabled;
private boolean isAccountNonLocked;
public User() {
super();
this.enabled=false;
this.isAccountNonLocked= true;
}
public User(User user) {
this.username = user.getUsername();
this.password = user.getPassword();
this.isActive = user.getIsActive();
this.roles = user.getRoles();
this.imageLocation=user.getImageLocation();
this.enabled= user.enabled;
this.isAccountNonLocked = user.isAccountNonLocked;
}
}
我的作用class如下:这还有@Data注解,生成Equals方法
@Entity
@Table(name = "role")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Role {
@Id
private Integer roleId;
private String role;
}
这是我的测试用例,其中包含对象实例之一。
@Test
public void testCreateVerificationToken() {
User user = new User();
String token = new String();
VerificationToken myToken = new VerificationToken();
myToken.setToken(token);
myToken.setUser(user);
myToken.setExpiryDate(myToken.calculateExpiryDate(24*60));
ArgumentCaptor<VerificationToken> entityCaptor = ArgumentCaptor.forClass(VerificationToken.class);
when(mocktokenRepository.save(entityCaptor.capture())).thenReturn(myToken);
verificationTokenServiceImpl.createVerificationToken(user, token);
assertEquals(entityCaptor.getValue(),myToken);
}
另一个对象实例化发生在这段代码中。
@Override
public void createVerificationToken(User user, String token) {
VerificationToken myToken = new VerificationToken();
myToken.setToken(token);
myToken.setUser(user);
myToken.setExpiryDate(myToken.calculateExpiryDate(24*60));
tokenRepository.save(myToken);
}
我无法理解为什么两个对象被认为不相等。如果需要,我很乐意提供更多详细信息。请帮忙。
提前致谢。
assertEquals
调用classVerificationToken
的equals
方法。您不覆盖此方法,因此使用 Object
的默认实现来检查实例相等性 (a == b
)。如果 entityCaptor.getValue()
不是 return 原始实例,而是例如序列化或克隆的副本,该测试将失败。
如果您希望对同一个实例进行 return 编辑,您应该使用 assertSame
并修复导致 return 不同实例的错误。如果你希望一个不同的实例被 returned,你应该首先做一个 assertNotSame
,在 VerificationToken
中实现 equals
和 hashcode
然后做 assertEquals
在 assertNotSame
.
之后
Date
具有毫秒精度,因此即使两个日期打印相同的值直到秒,equals
也可能 return 为假,因为它们相差毫秒。
您想做的是使用比毫秒更大的粒度。由于您的到期时间以分钟为单位,您可以将其用作最小时间单位并将 seconds/milliseconds 设置为零。这是实现该目标的快速方法。
public Date calculateExpiryDate(int expiryTimeInMinutes) {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.MINUTE, expiryTimeInMinutes);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal.getTime();
}
您正在比较的两个对象在 expiryDate
字段中具有不同的值。您正在使用 calculateExpiryDate
方法为代码中不同点的两个对象使用 new Date()
生成它们。他们不会平等。请注意,日期的精度是毫秒。
我不会建议您更改 calculateExpiryDate
实现以使测试通过,相反您可以将 expiryDate
设置为硬编码日期值。
我有两个内容相同的用户定义对象。但是 assertsEquals 反过来等于方法 returns false 对于那些对象。
这里是堆栈跟踪,其中也包含对象的 toString 内容。
java.lang.AssertionError: expected: com.xyz.test.model.VerificationToken<VerificationToken(id=null, token=, user=User(userId=null, username=null, email=null, password=null, isActive=0, roles=null, imageLocation=null, enabled=false, isAccountNonLocked=true), expiryDate=Sat Dec 22 22:48:49 IST 2018)> but was: com.xyz.test.model.VerificationToken<VerificationToken(id=null, token=, user=User(userId=null, username=null, email=null, password=null, isActive=0, roles=null, imageLocation=null, enabled=false, isAccountNonLocked=true), expiryDate=Sat Dec 22 22:48:49 IST 2018)>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:118)
at org.junit.Assert.assertEquals(Assert.java:144)
at ....
我对应的class如下。这有生成 Equals 方法的 lombak 的 @data 注释。
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class VerificationToken implements Serializable{
/**
*
*/
private static final long serialVersionUID = 8788934708305097680L;
private static final int EXPIRATION = 60 * 24;
@Id
private Long id;
private String token;
private User user;
private Date expiryDate;
public Date calculateExpiryDate(int expiryTimeInMinutes) {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.MINUTE, expiryTimeInMinutes);
return new Date(cal.getTime().getTime());
}
}
我的用户class如下。这也有 @Data 注释,它生成 Equals 方法
@Entity
@Table(name = "user")
@Data
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = -6480423780555564185L;
@Id
private Integer userId;
private String username;
private String email;
@JsonIgnore
private String password;
private int isActive;
private Set<Role> roles;
private String imageLocation;
private boolean enabled;
private boolean isAccountNonLocked;
public User() {
super();
this.enabled=false;
this.isAccountNonLocked= true;
}
public User(User user) {
this.username = user.getUsername();
this.password = user.getPassword();
this.isActive = user.getIsActive();
this.roles = user.getRoles();
this.imageLocation=user.getImageLocation();
this.enabled= user.enabled;
this.isAccountNonLocked = user.isAccountNonLocked;
}
}
我的作用class如下:这还有@Data注解,生成Equals方法
@Entity
@Table(name = "role")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Role {
@Id
private Integer roleId;
private String role;
}
这是我的测试用例,其中包含对象实例之一。
@Test
public void testCreateVerificationToken() {
User user = new User();
String token = new String();
VerificationToken myToken = new VerificationToken();
myToken.setToken(token);
myToken.setUser(user);
myToken.setExpiryDate(myToken.calculateExpiryDate(24*60));
ArgumentCaptor<VerificationToken> entityCaptor = ArgumentCaptor.forClass(VerificationToken.class);
when(mocktokenRepository.save(entityCaptor.capture())).thenReturn(myToken);
verificationTokenServiceImpl.createVerificationToken(user, token);
assertEquals(entityCaptor.getValue(),myToken);
}
另一个对象实例化发生在这段代码中。
@Override
public void createVerificationToken(User user, String token) {
VerificationToken myToken = new VerificationToken();
myToken.setToken(token);
myToken.setUser(user);
myToken.setExpiryDate(myToken.calculateExpiryDate(24*60));
tokenRepository.save(myToken);
}
我无法理解为什么两个对象被认为不相等。如果需要,我很乐意提供更多详细信息。请帮忙。
提前致谢。
assertEquals
调用classVerificationToken
的equals
方法。您不覆盖此方法,因此使用 Object
的默认实现来检查实例相等性 (a == b
)。如果 entityCaptor.getValue()
不是 return 原始实例,而是例如序列化或克隆的副本,该测试将失败。
如果您希望对同一个实例进行 return 编辑,您应该使用 assertSame
并修复导致 return 不同实例的错误。如果你希望一个不同的实例被 returned,你应该首先做一个 assertNotSame
,在 VerificationToken
中实现 equals
和 hashcode
然后做 assertEquals
在 assertNotSame
.
Date
具有毫秒精度,因此即使两个日期打印相同的值直到秒,equals
也可能 return 为假,因为它们相差毫秒。
您想做的是使用比毫秒更大的粒度。由于您的到期时间以分钟为单位,您可以将其用作最小时间单位并将 seconds/milliseconds 设置为零。这是实现该目标的快速方法。
public Date calculateExpiryDate(int expiryTimeInMinutes) {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.MINUTE, expiryTimeInMinutes);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal.getTime();
}
您正在比较的两个对象在 expiryDate
字段中具有不同的值。您正在使用 calculateExpiryDate
方法为代码中不同点的两个对象使用 new Date()
生成它们。他们不会平等。请注意,日期的精度是毫秒。
我不会建议您更改 calculateExpiryDate
实现以使测试通过,相反您可以将 expiryDate
设置为硬编码日期值。