数据库 测试数据生成_测试数据生成器和对象母亲:另一种外观
數(shù)據(jù)庫(kù) 測(cè)試數(shù)據(jù)生成
在測(cè)試中構(gòu)造對(duì)象通常是一項(xiàng)艱巨的工作,通常會(huì)產(chǎn)生大量可重復(fù)且難以閱讀的代碼。 有兩種用于處理復(fù)雜測(cè)試數(shù)據(jù)的常見(jiàn)解決方案: Object Mother和Test Data Builder 。 兩者都有優(yōu)點(diǎn)和缺點(diǎn),但是(巧妙地)結(jié)合可以為您的測(cè)試帶來(lái)新的質(zhì)量。
注意:關(guān)于Object Mother和Test Data Builder ,已經(jīng)有很多文章可以找到,因此我將使我的描述非常簡(jiǎn)潔。
對(duì)象母親
不久,“ 對(duì)象母親”是一組工廠方法,使我們可以在測(cè)試中創(chuàng)建類似的對(duì)象:
// Object Mother public class TestUsers {public static User aRegularUser() {return new User("John Smith", "jsmith", "42xcc", "ROLE_USER");}// other factory methods}// arrange User user = TestUsers.aRegularUser(); User adminUser = TestUsers.anAdmin();每次需要數(shù)據(jù)變化稍有不同的用戶時(shí),都會(huì)創(chuàng)建新的工廠方法,這會(huì)使“ Object Mother隨時(shí)間增長(zhǎng)。 這是Object Mother的缺點(diǎn)之一。 可以通過(guò)引入Test Data Builder解決此問(wèn)題。
測(cè)試數(shù)據(jù)生成器
Test Data Builder使用Builder模式在單元測(cè)試中創(chuàng)建對(duì)象。 一的簡(jiǎn)短提醒Builder :
構(gòu)建器模式是對(duì)象創(chuàng)建軟件設(shè)計(jì)模式。 […]構(gòu)建器模式的目的是找到可伸縮構(gòu)造函數(shù)反模式的解決方案。
讓我們看一下Test Data Builder的示例:
public class UserBuilder {public static final String DEFAULT_NAME = "John Smith";public static final String DEFAULT_ROLE = "ROLE_USER";public static final String DEFAULT_PASSWORD = "42";private String username;private String password = DEFAULT_PASSWORD;private String role = DEFAULT_ROLE;private String name = DEFAULT_NAME;private UserBuilder() {}public static UserBuilder aUser() {return new UserBuilder();}public UserBuilder withName(String name) {this.name = name;return this;}public UserBuilder withUsername(String username) {this.username = username;return this;}public UserBuilder withPassword(String password) {this.password = password;return this;}public UserBuilder withNoPassword() {this.password = null;return this;}public UserBuilder inUserRole() {this.role = "ROLE_USER";return this;}public UserBuilder inAdminRole() {this.role = "ROLE_ADMIN";return this;}public UserBuilder inRole(String role) {this.role = role;return this;}public UserBuilder but() {return UserBuilder.aUser().inRole(role).withName(name).withPassword(password).withUsername(username);}public User build() {return new User(name, username, password, role);} }在我們的測(cè)試中,我們可以如下使用構(gòu)建器:
UserBuilder userBuilder = UserBuilder.aUser().withName("John Smith").withUsername("jsmith");User user = userBuilder.build(); User admin = userBuilder.but().withNoPassword().inAdminRole();上面的代碼看起來(lái)非常不錯(cuò)。 我們擁有一個(gè)流暢的API,可以提高測(cè)試代碼的可讀性,并且可以肯定地消除了使用Object Mother需要多種工廠方法來(lái)處理測(cè)試中需要的對(duì)象變化的問(wèn)題。
請(qǐng)注意,我添加了一些默認(rèn)屬性值,這些默認(rèn)值可能與大多數(shù)測(cè)試無(wú)關(guān)。 但是,由于我們將它們定義為公共常量,因此可以在斷言中使用它們。
注意:本文使用的示例相對(duì)簡(jiǎn)單。 它用于可視化解決方案。
對(duì)象母親和測(cè)試數(shù)據(jù)生成器結(jié)合
兩種解決方案都不完美。 但是,如果我們將它們結(jié)合在一起怎么辦? 想象一下, Object Mother返回一個(gè)Test Data Builder 。 有了這個(gè),您就可以在調(diào)用終端操作之前操縱構(gòu)建器狀態(tài)。 這是一種模板。
看下面的例子:
public final class TestUsers {public static UserBuilder aDefaultUser() {return UserBuilder.aUser().inUserRole().withName("John Smith").withUsername("jsmith");}public static UserBuilder aUserWithNoPassword() {return UserBuilder.aUser().inUserRole().withName("John Smith").withUsername("jsmith").withNoPassword();}public static UserBuilder anAdmin() {return UserBuilder.aUser().inAdminRole().withName("Chris Choke").withUsername("cchoke").withPassword("66abc");} }現(xiàn)在, TestUsers提供了用于在我們的測(cè)試中創(chuàng)建類似測(cè)試數(shù)據(jù)的工廠方法。 它返回一個(gè)構(gòu)建器實(shí)例,因此我們能夠根據(jù)需要在測(cè)試中快速而完美地修改對(duì)象:
UserBuilder user = TestUsers.aUser(); User admin = user.but().withNoPassword().build();好處是巨大的。 我們有一個(gè)用于創(chuàng)建相似對(duì)象的模板,如果我們需要在使用返回對(duì)象之前修改返回對(duì)象的狀態(tài),則我們擁有構(gòu)建器的強(qiáng)大功能。
豐富測(cè)試數(shù)據(jù)生成器
考慮以上內(nèi)容時(shí),我不確定是否真的需要單獨(dú)的Object Mother 。 我們可以輕松地將方法從Object Mother直接移動(dòng)到Test Data Builder :
public class UserBuilder {public static final String DEFAULT_NAME = "John Smith";public static final String DEFAULT_ROLE = "ROLE_USER";public static final String DEFAULT_PASSWORD = "42";// field declarations omitted for readabilityprivate UserBuilder() {}public static UserBuilder aUser() {return new UserBuilder();}public static UserBuilder aDefaultUser() {return UserBuilder.aUser().withUsername("jsmith");}public static UserBuilder aUserWithNoPassword() {return UserBuilder.aDefaultUser().withNoPassword();}public static UserBuilder anAdmin() {return UserBuilder.aUser().inAdminRole();}// remaining methods omitted for readability}因此,我們可以在單個(gè)類中維護(hù)User數(shù)據(jù)的創(chuàng)建。
請(qǐng)注意,在此Test Data Builder是測(cè)試代碼。 如果我們?cè)谏a(chǎn)代碼中已經(jīng)有一個(gè)生成器,那么創(chuàng)建一個(gè)Object Mother返回一個(gè)Builder實(shí)例聽(tīng)起來(lái)是一個(gè)更好的解決方案。
可變對(duì)象呢?
當(dāng)涉及可變對(duì)象時(shí), Test Data Builder方法可能存在一些缺點(diǎn)。 在許多應(yīng)用程序中,我主要處理可變對(duì)象(又稱為beans或anemic data model ),也許你們中的許多人也這樣做。
從理論上講, Builder模式用于創(chuàng)建不變的價(jià)值對(duì)象。 通常,如果我們處理可變對(duì)象,乍一看, Test Data Builder看起來(lái)就像是重復(fù)的:
// Mutable class with setters and getters class User {private String name;public String getName() { ... }public String setName(String name) { ... }// ... }public class UserBuilder {private User user = new User();public UserBuilder withName(String name) {user.setName(name);return this;}// other methodspublic User build() {return user;} }在測(cè)試中,我們可以創(chuàng)建一個(gè)如下用戶:
User aUser = UserBuiler.aUser().withName("John").withPassword("42abc").build();代替:
User aUser = new User(); aUser.setName("John"); aUser.setPassword("42abc");在這種情況下,創(chuàng)建Test Data Builder是一個(gè)折衷方案 。 它需要編寫(xiě)更多需要維護(hù)的代碼。 另一方面,可讀性大大提高。
摘要
在單元測(cè)試中管理測(cè)試數(shù)據(jù)并非易事。 如果找不到合適的解決方案,那么最終將獲得大量難以理解和維護(hù)的樣板代碼。 另一方面,沒(méi)有解決該問(wèn)題的靈丹妙藥。 我嘗試了許多方法。 根據(jù)問(wèn)題的大小,我需要選擇一種不同的方法,有時(shí)在一個(gè)項(xiàng)目中結(jié)合使用多種方法。
您如何處理測(cè)試中的數(shù)據(jù)構(gòu)建?
資源資源
- Petri Kainulainen: 編寫(xiě)干凈的測(cè)試–被認(rèn)為有害的新方法
- Growing Object-Oriented Software, Guided by Tests –第22章: Constructing Complex Test Data 。
翻譯自: https://www.javacodegeeks.com/2014/06/test-data-builders-and-object-mother-another-look.html
數(shù)據(jù)庫(kù) 測(cè)試數(shù)據(jù)生成
總結(jié)
以上是生活随笔為你收集整理的数据库 测试数据生成_测试数据生成器和对象母亲:另一种外观的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 测量时间:从Java到内核再到
- 下一篇: Apache Derby数据库JVM安全