这并不是要成为技术含量很高的职位。 这篇文章的目的是为您提供一些指导,以使您的JUnit测试生活更加轻松,使您能够在几分钟内编写复杂的测试场景,并具有易于阅读的测试优势。
单元测试中有两个主要部分,需要编写许多引导程序代码:
- 设置部分:构建初始状态需要构建将被馈送到SUT(被测系统)的初始对象
- 断言部分:构造输出对象的所需图像,并仅对所需数据进行断言。
为了降低构建用于测试的对象的复杂性,我建议在以下解释中使用Builder模式:
这是域对象:
public class Employee {private int id;private String name;private Department department;//setters, getters, hashCode, equals, toString methods
此域对象的生成器如下所示:
public class EmployeeBuilder {private Employee employee;public EmployeeBuilder() {employee = new Employee();}public static EmployeeBuilder defaultValues() {return new EmployeeBuilder();}public static EmployeeBuilder clone(Employee toClone) {EmployeeBuilder builder = defaultValues();builder.setId(toClone.getId());builder.setName(toClone.getName());builder.setDepartment(toClone.getDepartment());return builder;}public static EmployeeBuilder random() {EmployeeBuilder builder = defaultValues();builder.setId(getRandomInteger(0, 1000));builder.setName(getRandomString(20));builder.setDepartment(Department.values()[getRandomInteger(0, Department.values().length - 1)]);return builder;}public EmployeeBuilder setId(int id) {employee.setId(id);return this;}public EmployeeBuilder setName(String name) {employee.setName(name);return this;}public EmployeeBuilder setDepartment(Department dept) {employee.setDepartment(dept);return this;}public Employee build() {return employee;}
}
如您所见,我们有一些工厂方法:
public static EmployeeBuilder defaultValues()public static EmployeeBuilder clone(Employee toClone)public static EmployeeBuilder random()
这些方法返回不同的构建器:
- defaultValues:每个字段的一些硬编码值(或Java默认值-当前实现)
- clone:将获取初始对象中的所有值,并使您可以更改其中一些值
- random:将为每个字段生成随机值。 当您有很多字段在测试中不需要时非常有用,但是您需要将它们初始化。 getRandom *方法是在另一个类中静态定义的。
您可以添加其他方法来根据需要初始化构建器。
此外,构建器还可以处理一些不那么容易构建和更改的对象。 例如,让我们稍微更改Employee对象,使其不可变:
public class Employee {private final int id;private final String name;private final Department department;...
}
现在,我们失去了按需更改字段的可能性。 但是使用以下形式的构建器,我们可以在构造对象时重新获得这种可能性:
public class ImmutableEmployeeBuilder {private int id;private String name;private Department department;public ImmutableEmployeeBuilder() {}public static ImmutableEmployeeBuilder defaultValues() {return new ImmutableEmployeeBuilder();}public static ImmutableEmployeeBuilder clone(Employee toClone) {ImmutableEmployeeBuilder builder = defaultValues();builder.setId(toClone.getId());builder.setName(toClone.getName());builder.setDepartment(toClone.getDepartment());return builder;}public static ImmutableEmployeeBuilder random() {ImmutableEmployeeBuilder builder = defaultValues();builder.setId(getRandomInteger(0, 1000));builder.setName(getRandomString(20));builder.setDepartment(Department.values()[getRandomInteger(0, Department.values().length - 1)]);return builder;}public ImmutableEmployeeBuilder setId(int id) {this.id = id;return this;}public ImmutableEmployeeBuilder setName(String name) {this.name = name;return this;}public ImmutableEmployeeBuilder setDepartment(Department dept) {this.department = dept;return this;}public ImmutableEmployee build() {return new ImmutableEmployee(id, name, department);}
}
当我们难以构造对象或需要更改最终字段时,这非常有用。
这是它的最终结果:
没有建设者:
@Testpublic void changeRoleTestWithoutBuilders() {// building the initial stateEmployee employee = new Employee();employee.setId(1);employee.setDepartment(Department.DEVELOPEMENT);employee.setName("John Johnny");// testing the SUTEmployeeManager employeeManager = new EmployeeManager();employeeManager.changeRole(employee, Department.MANAGEMENT);// building the expectationsEmployee expectedEmployee = new Employee();expectedEmployee.setId(employee.getId());expectedEmployee.setDepartment(Department.MANAGEMENT);expectedEmployee.setName(employee.getName());// assertionsassertThat(employee, is(expectedEmployee));}
与建设者:
@Testpublic void changeRoleTestWithBuilders() {// building the initial stateEmployee employee = EmployeeBuilder.defaultValues().setId(1).setName("John Johnny").setDepartment(Department.DEVELOPEMENT).build();// building the expectationsEmployee expectedEmployee = EmployeeBuilder.clone(employee).setDepartment(Department.MANAGEMENT).build();// testing the SUTEmployeeManager employeeManager = new EmployeeManager();employeeManager.changeRole(employee, Department.MANAGEMENT);// assertionsassertThat(employee, is(expectedEmployee));}
如您所见,测试的大小要小得多,对象的构造也变得更加简单(如果代码格式更好,也会更好)。 如果您具有更复杂的域对象(在实际应用程序中,尤其是在遗留代码中),则差异更大。
玩得开心!
参考:来自Java出现日历博客的JCG合作伙伴 Stefan Bulzan 在JUnit测试中使用了Builder模式 。
翻译自: https://www.javacodegeeks.com/2012/12/using-builder-pattern-in-junit-tests.html