内置假对象
盡管模擬對象是進行單元測試的理想工具,但通過模擬框架進行模擬可能會將您的單元測試變成難以維護的混亂。
這種復(fù)雜性的根本原因是我們的對象太大。 他們有很多方法,這些方法返回其他對象,這些對象也有方法。 當(dāng)將此類對象的模擬版本作為參數(shù)傳遞時,我們應(yīng)確保其所有方法都返回有效對象。
這導(dǎo)致不可避免的復(fù)雜性,這使得單元測試?yán)速M幾乎不可能維護。
對象層次結(jié)構(gòu)
以jcabi-dynamo的Region接口為例(為簡潔起見,此代碼段和本文中的所有其他代碼段均進行了簡化):
public interface Region {Table table(String name); }它的table()方法返回Table接口的實例,該實例具有自己的方法:
public interface Table {Frame frame();Item put(Attributes attrs);Region region(); }由frame()方法返回的接口Frame也具有自己的方法。 等等。 為了創(chuàng)建一個正確的接口Region模擬實例,通常會創(chuàng)建許多其他模擬對象。 使用Mockito時 ,它將如下所示:
public void testMe() {// many more lines here...Frame frame = Mockito.mock(Frame.class);Mockito.doReturn(...).when(frame).iterator();Table table = Mockito.mock(Table.class);Mockito.doReturn(frame).when(table).frame();Region region = Mockito.mock(Region.class);Mockito.doReturn(table).when(region).table(Mockito.anyString()); }所有這些只是實際測試之前的腳手架。
樣例用例
假設(shè)您正在開發(fā)一個項目,該項目使用jcabi-dynamo來管理DynamoDB中的數(shù)據(jù)。 您的課程可能類似于以下內(nèi)容:
public class Employee {private final String name;private final Region region;public Employee(String empl, Region dynamo) {this.name = empl;this.region = dynamo;}public Integer salary() {return Integer.parseInt(this.region.table("employees").frame().where("name", this.name).iterator().next().get("salary").getN());} }您可以想象,例如使用Mockito對此類進行單元測試將有多困難。 首先,我們必須模擬Region接口。 然后,我們必須模擬一個Table接口,并確保它由table()方法返回。 然后,我們必須模擬一個Frame接口,等等。
單元測試將比類本身更長。 除此之外,它的真正目的(即測試雇員薪水的收回)對讀者而言并不明顯。
而且,當(dāng)我們需要測試相似類的相似方法時,我們將需要從頭開始重新進行此模擬。 同樣,多行代碼看起來與我們已經(jīng)編寫的代碼非常相似。
假班
解決方案是創(chuàng)建偽造的類并將其與真實的類一起運送。 這就是jcabi-dynamo所做的。 只需查看其JavaDoc即可 。 有一個名為com.jcabi.dynamo.mock的軟件包,其中僅包含偽類,僅適用于單元測試。
即使它們的唯一目的是優(yōu)化單元測試,我們也將它們與生產(chǎn)代碼一起放在同一JAR軟件包中。
使用偽類MkRegion時,測試結(jié)果如下所示:
public class EmployeeTest {public void canFetchSalaryFromDynamoDb() {Region region = new MkRegion(new H2Data().with("employees", new String[] {"name"},new String[] {"salary"}));region.table("employees").put(new Attributes().with("name", "Jeff").with("salary", new AttributeValue().withN(50000)));Employee emp = new Employee("Jeff", region);assertThat(emp.salary(), equalTo(50000))} }這個測試對我來說很明顯。 首先,我們創(chuàng)建一個偽造的DynamoDB區(qū)域,該區(qū)域可在H2Data存儲(內(nèi)存中的H2數(shù)據(jù)庫)之上H2Data 。 該存儲將準(zhǔn)備好用于具有哈希鍵name和單個salary屬性的單個employees表。
然后,我們在表中放入記錄,其中包含哈希Jeff和薪水50000 。
最后,我們創(chuàng)建一個Employee類的實例,并檢查它如何從DynamoDB獲取薪水。
我目前正在與幾乎所有正在使用的開源庫中進行相同的操作。 我正在創(chuàng)建一組偽造的類,以簡化庫內(nèi)部及其用戶的測試。
相關(guān)文章
您可能還會發(fā)現(xiàn)以下有趣的帖子:
- Glenford Myers撰寫的軟件測試藝術(shù)
- Maven Build中的CasperJS測試
- Hamcrest的XML / XPath匹配器
- 錯誤歡迎
- Phantomjs作為HTML驗證器
翻譯自: https://www.javacodegeeks.com/2014/09/built-in-fake-objects.html
總結(jié)
- 上一篇: 存死期的钱能提前取吗?
- 下一篇: 工商银行的原油星期六0点不能交易吗?