這并不是要成為技術含量很高的職位。 這篇文章的目的是為您提供一些指導,以使您的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