Java实体类及其单元测试的良好实践
我只是想确认一下你们是否认为这是一个好的做法:Java实体类及其单元测试的良好实践,java,Java,我只是想确认一下你们是否认为这是一个好的做法: 用java编写实体类,并使用javax.validation.constraints注释进行一些验证 编写单元测试以断言验证 编写单元测试来断言getter和setter,因为这是一种断言类包含我们需要的所有字段的方法 公共类地址验证测试{ 私人静态验证器工厂; 私有静态验证器; 私有静态最终字符串地址\u LINE1=“地址行1”; 私有静态最终字符串地址\u LINE2=“地址行2”; 私有静态最终字符串ADDRESS\u CITY=“AD
- 用java编写实体类,并使用javax.validation.constraints注释进行一些验证
- 编写单元测试以断言验证
- 编写单元测试来断言getter和setter,因为这是一种断言类包含我们需要的所有字段的方法
公共类地址验证测试{
私人静态验证器工厂;
私有静态验证器;
私有静态最终字符串地址\u LINE1=“地址行1”;
私有静态最终字符串地址\u LINE2=“地址行2”;
私有静态最终字符串ADDRESS\u CITY=“ADDRESS CITY”;
私有静态最终字符串地址\u COUNTRY\u CODE=“IT”;
私有静态最终客户端地址_Client=new Client();
@以前
公共静态void createValidator(){
validatorFactory=Validation.buildDefaultValidatorFactory();
validator=validatorFactory.getValidator();
}
@毕竟
公共静态无效关闭(){
validatorFactory.close();
}
@试验
公共空间应避免破坏(){
//鉴于:
地址=地址.builder()
.line1(地址_line1)
.line2(地址_line2)
.城市(地址\城市)
.countryCode(地址\国家\代码)
.客户(地址\客户)
.build();
//当:
设置违规行为
=validator.validate(地址);
//然后:
assertTrue(inflictions.isEmpty());
}
@试验
公共无效应检测有效线1(){
//名称太短:
地址=地址.builder()
.1行(“L”)
.line2(地址_line2)
.城市(地址\城市)
.countryCode(地址\国家\代码)
.客户(地址\客户)
.build();
//当:
设置冲突=validator.validate(地址);
//然后:
assertEquals(1,违例项.size());
ConstraintViolation违规=违规。迭代器().next();
assertEquals(“大小必须介于2和40之间”,违例。getMessage());
assertEquals(“line1”,违例.getPropertyPath().toString());
assertEquals(“L”,违例.getInvalidValue());
}
@试验
public void应检测有效线2(){
//名称太短:
地址=地址.builder()
.line1(地址_line1)
.第2行(“L”)
.城市(地址\城市)
.countryCode(地址\国家\代码)
.客户(地址\客户)
.build();
//当:
设置冲突=validator.validate(地址);
//然后:
assertEquals(1,违例项.size());
ConstraintViolation违规=违规。迭代器().next();
assertEquals(“大小必须介于2和40之间”,违例。getMessage());
assertEquals(“line2”,违例。getPropertyPath().toString());
assertEquals(“L”,违例.getInvalidValue());
}
@试验
public void shouldDetectInvalidCity(){
//名称太短:
地址=地址.builder()
.line1(地址_line1)
.line2(地址_line2)
.城市(“aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbddddddddddddddeeeeeeeeeeeeeeeeffffffffffffggggggggggg”)
.countryCode(地址\国家\代码)
.客户(地址\客户)
.build();
//当:
设置冲突=validator.validate(地址);
//然后:
assertEquals(1,违例项.size());
ConstraintViolation违规=违规。迭代器().next();
assertEquals(“大小必须介于2和40之间”,违例。getMessage());
assertEquals(“城市”,违反.getPropertyPath().toString());
资产质量(“aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbb ddddddddddddeeeeeeeeeeeeeeeeffffffffffffggggggggggg”,违规。getInvalidValue());
}
@试验
public void应检测到ValidCountryCode(){
//名称太短:
地址=地址.builder()
.line1(地址_line1)
.line2(地址_line2)
.城市(地址\城市)
.countryCode(“ITA”)
.客户(地址\客户)
.build();
//当:
设置冲突=validator.validate(地址);
//然后:
assertEquals(1,违例项.size());
ConstraintViolation违规=违规。迭代器().next();
assertEquals(“大小必须介于2和2之间”,违例。getMessage());
assertEquals(“countryCode”,violation.getPropertyPath().toString());
assertEquals(“ITA”,违例.getInvalidValue());
}
@试验
public void shouldDetectInvalidClient(){
//名称太短:
地址=地址.builder()
.line1(地址_line1)
.line2(地址_line2)
.城市(地址\城市)
.countryCode(地址\国家\代码)
.build();
//当:
设置冲突=validator.validate(地址);
//然后:
assertEquals(1,违例项.size());
ConstraintViolation违规=违规。迭代器().next();
assertEquals(“不得为null”,违例。getMessage());
assertEquals(“客户端”,冲突.getPropertyPath().toString());
assertEquals(null,违例。getInvalidValue());
}
}
请注意,实际上您只测试了所使用内容的一小部分:例如,所有和无参数构造函数、setter、hashCode()
和equals()
都未测试
现在,这是一个好的实践来测试吗?
我想是的。使用Lombok注释生成一些实现,您只能在运行时(测试和应用程序运行时)验证这些实现的行为。
例如,注释可能不会产生预期的行为,因为与另一个注释冲突或使用不当(例如,如果生成的方法中存在循环,则会出现stackoverflow错误)您可能只会在运行时发现这些问题,充其量只是一个明确说明问题的异常,或者充其量是一个潜在的错误,其根本原因不是obvi
@Builder
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@ToString(exclude = "client")
@Data
@Entity
@Table(name = "addresses")
public class Address extends BaseEntity {
private static final long serialVersionUID = -5966581124342250987L;
@NotNull
@Size(min = 2, max = 40)
@Column(name = "line1", nullable = false, length = 40)
private String line1;
@Size(min = 2, max = 40)
@Column(name = "line2", length = 40)
private String line2;
@NotNull
@Size(min = 2, max = 40)
@Column(name = "city", length = 40)
private String city;
@NotNull
@Size(min = 2, max = 2)
@Column(name = "country_code", length = 2)
private String countryCode; //code ISO 3166 two-letter country codes
@NotNull
@EqualsAndHashCode.Exclude
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "client_id")
private Client client;
}
class AddressTest {
private static final String ADDRESS_LINE1 = "Address line 1";
private static final String ADDRESS_LINE2 = "Address line 2";
private static final String ADDRESS_CITY = "Address City";
private static final String ADDRESS_COUNTRY_CODE = "IT";
private static final Client ADDRESS_CLIENT = new Client();
private Address address;
@BeforeEach
void setUp() {
address = Address.builder()
.line1( ADDRESS_LINE1 )
.line2( ADDRESS_LINE2 )
.city( ADDRESS_CITY )
.countryCode( ADDRESS_COUNTRY_CODE )
.client( ADDRESS_CLIENT )
.build();
}
@Test
public void CreateAddress_AssertBasicFields() {
assertEquals(ADDRESS_LINE1, address.getLine1());
assertEquals(ADDRESS_LINE2, address.getLine2());
assertEquals(ADDRESS_CITY, address.getCity());
assertEquals(ADDRESS_COUNTRY_CODE, address.getCountryCode());
}
@Test
public void CreateAddress_AssertClient() {
assertEquals(ADDRESS_CLIENT, address.getClient());
}
}
public class AddressValidationTest {
private static ValidatorFactory validatorFactory;
private static Validator validator;
private static final String ADDRESS_LINE1 = "Address line 1";
private static final String ADDRESS_LINE2 = "Address line 2";
private static final String ADDRESS_CITY = "Address City";
private static final String ADDRESS_COUNTRY_CODE = "IT";
private static final Client ADDRESS_CLIENT = new Client();
@BeforeAll
public static void createValidator() {
validatorFactory = Validation.buildDefaultValidatorFactory();
validator = validatorFactory.getValidator();
}
@AfterAll
public static void close() {
validatorFactory.close();
}
@Test
public void shouldHaveNoViolations() {
//given:
Address address = Address.builder()
.line1( ADDRESS_LINE1 )
.line2( ADDRESS_LINE2 )
.city( ADDRESS_CITY )
.countryCode( ADDRESS_COUNTRY_CODE )
.client( ADDRESS_CLIENT )
.build();
//when:
Set<ConstraintViolation<Address>> violations
= validator.validate(address);
//then:
assertTrue(violations.isEmpty());
}
@Test
public void shouldDetectInvalidLine1() {
//given too short name:
Address address = Address.builder()
.line1( "L" )
.line2( ADDRESS_LINE2 )
.city( ADDRESS_CITY )
.countryCode( ADDRESS_COUNTRY_CODE )
.client( ADDRESS_CLIENT )
.build();
//when:
Set<ConstraintViolation<Address>> violations = validator.validate(address);
//then:
assertEquals(1, violations.size());
ConstraintViolation<Address> violation = violations.iterator().next();
assertEquals("size must be between 2 and 40", violation.getMessage());
assertEquals("line1", violation.getPropertyPath().toString());
assertEquals("L", violation.getInvalidValue());
}
@Test
public void shouldDetectInvalidLine2() {
//given too short name:
Address address = Address.builder()
.line1( ADDRESS_LINE1 )
.line2( "L" )
.city( ADDRESS_CITY )
.countryCode( ADDRESS_COUNTRY_CODE )
.client( ADDRESS_CLIENT )
.build();
//when:
Set<ConstraintViolation<Address>> violations = validator.validate(address);
//then:
assertEquals(1, violations.size());
ConstraintViolation<Address> violation = violations.iterator().next();
assertEquals("size must be between 2 and 40", violation.getMessage());
assertEquals("line2", violation.getPropertyPath().toString());
assertEquals("L", violation.getInvalidValue());
}
@Test
public void shouldDetectInvalidCity() {
//given too short name:
Address address = Address.builder()
.line1( ADDRESS_LINE1 )
.line2( ADDRESS_LINE2 )
.city( "Aaaaaaaaaa AAAAAAAAAAA BBBBBBBBBBb dddddddddddddd eeeeeeeeeeeeee ffffffffffff ggggggggggg" )
.countryCode( ADDRESS_COUNTRY_CODE )
.client( ADDRESS_CLIENT )
.build();
//when:
Set<ConstraintViolation<Address>> violations = validator.validate(address);
//then:
assertEquals( 1, violations.size());
ConstraintViolation<Address> violation = violations.iterator().next();
assertEquals("size must be between 2 and 40", violation.getMessage());
assertEquals("city", violation.getPropertyPath().toString());
assertEquals("Aaaaaaaaaa AAAAAAAAAAA BBBBBBBBBBb dddddddddddddd eeeeeeeeeeeeee ffffffffffff ggggggggggg", violation.getInvalidValue());
}
@Test
public void shouldDetectInvalidCountryCode() {
//given too short name:
Address address = Address.builder()
.line1( ADDRESS_LINE1 )
.line2( ADDRESS_LINE2 )
.city( ADDRESS_CITY )
.countryCode( "ITA" )
.client( ADDRESS_CLIENT )
.build();
//when:
Set<ConstraintViolation<Address>> violations = validator.validate(address);
//then:
assertEquals( 1, violations.size());
ConstraintViolation<Address> violation = violations.iterator().next();
assertEquals("size must be between 2 and 2", violation.getMessage());
assertEquals("countryCode", violation.getPropertyPath().toString());
assertEquals("ITA", violation.getInvalidValue());
}
@Test
public void shouldDetectInvalidClient() {
//given too short name:
Address address = Address.builder()
.line1( ADDRESS_LINE1 )
.line2( ADDRESS_LINE2 )
.city( ADDRESS_CITY )
.countryCode( ADDRESS_COUNTRY_CODE )
.build();
//when:
Set<ConstraintViolation<Address>> violations = validator.validate(address);
//then:
assertEquals( 1, violations.size());
ConstraintViolation<Address> violation = violations.iterator().next();
assertEquals("must not be null", violation.getMessage());
assertEquals("client", violation.getPropertyPath().toString());
assertEquals(null, violation.getInvalidValue());
}
}
@ToString(exclude = "client")
@ToString
Address address = Address.builder()
.line1( randomAddress() )
.city( randomCity() )
.countryCode( randomCountry() )
.build()