java - Java 实体类及其单元测试的良好实践
问题描述
我只是想确认你们是否认为这是一个好习惯:
- 使用 javax.validation.constraints 注释在 java 中编写带有一些验证的实体类
- 编写单元测试来断言验证
- 编写单元测试来断言 getter 和 setter,因为它是断言类包含我们需要的所有字段的一种方式
@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());
}
}
解决方案
实体是数据库的增强镜像(实例是 SSOT,类是 SVOT),M im MVC,它们是 bean。是否应该对 bean 进行单元测试:不。
您所做的是在实体中混合 M 和 C。C是否应该进行单元测试?Yes!!!
.
所以你真的应该测试它们!
推荐阅读
- sql - Min/Max timestamp of a slow changing dimension
- asp.net - Secure Connection Failed. The page you are trying to view cannot be shown because the authenticity of the received data could not be verified
- python - speed up regex finditer for large dataset
- python - Sorting by columns after grouping generating error
- c++ - 模板参数类型被编译器视为完整,但其定义尚不可见
- javascript - React Native Fetch 函数清除状态
- android - Why does my "content://" URI return a null InputStream, even though I can read from the ZipResourceFile object?
- c++ - 如何为“MyClass object = f(x)”重载 = 运算符?
- git - Git 客户端软件一次提取多个远程存储库
- java - 从 EditText 中检索文本