關(guān)于單元測試中可維護(hù)性的2個關(guān)注點

關(guān)于單元測試的內(nèi)容很多,關(guān)于可維護(hù)性的內(nèi)容也很多,在這里主要關(guān)注單元測試代碼可維護(hù)性中的兩點。

  • 重復(fù)

  • 條件測試

重復(fù)


重復(fù):同一概念,多處表達(dá)。從形式可以把重復(fù)分類為:代碼內(nèi)容完全一樣,代碼結(jié)構(gòu)相同,結(jié)構(gòu)不同但語義相近。

獲取重復(fù)的感性認(rèn)識

代碼完全相同

在多個文件中到處充斥著

log("當(dāng)前網(wǎng)絡(luò)不可達(dá)!");

在比如, 下面的兩處空字符串""完全一樣,兩處 "plainText"完全一樣.

public class TemplateTest {
    @Test
    public void emptyTemplate() throws Exception {
        assertEquals("", new Template("").toString());
    }

    @Test
    public void plainTextTemplate() throws Exception {
        assertEquals("plainText", new Template("plainText").toString());
    }
}
代碼結(jié)構(gòu)相同

比如下面的代碼,結(jié)構(gòu)是相同的

public class TemplateTest {
    @Test
    public void emptyTemplate() throws Exception {
       String template = "";
        assertEquals(template, new Template(template).toString());
    }

    @Test
    public void plainTextTemplate() throws Exception {
        String template = "plainText",;
        assertEquals(template, new Template(template).toString());
    }
}
<a name="semanteme_repeat"></a>結(jié)構(gòu)不同但語義相近

下面兩處內(nèi)容、結(jié)構(gòu)都不同相同。但可以抽象為通過某種條件對一個集合進(jìn)行過濾,最后得到目標(biāo)集合。

@Test
    public void groupShouldContainTwoSupervisors() {
        List<Employee> all = group.list();
        List<Employee> all = new ArrayList<>(all);
        Iterator<Employee> i = employees.iterator();
        while(i.hasNext()) {
            Employee employee = i.next();
            if (!employee.isSupervisor()) {
                i.remove();
            }
        }

        assertEquals(2, employee.size());
    }

    @Test

    public void groupShouldContainFiveNewcomers() {
        List<Employee> newcomers = new ArrayList<>();
        for (Employee employee : group.list()) {
            DateTime oneYearAgo = DateTime.now().minusYears(1);
            if (employee.startingDate().isAfter(oneYearAgo)) {
                newcomers.add(employee);
            }
        }

        assertEquals(5, newcomers.size());
    }

去重后

@Test
    public void groupShouldContainTwoSupervisors() {
          groupShouldContains(2, group.list(), employeeFilter);
    }

    @Test
    public void groupShouldContainFiveNewcomers() {
        groupShouldContains(2, group.list, customFilter);
    }

抽象接口

public interface Filter<T> {
        List<T> filter(List<T> objects);
}

抽取公共方法

 private void groupShouldContains(int expectedCount, List group, Filter filter) {
     List list = filter.filter(group);
     assertEquals(expectedCount, list.size());
}

怎么去掉重復(fù)

根據(jù)重復(fù)的概念---“同一個概念,在多處表達(dá)” 所以我們要第一步先抽象出表達(dá)的概念。第二步 把所有出現(xiàn)重復(fù)的地方用我們抽象的概念形成一個統(tǒng)一的命題。

第一步 抽象概念

我要打印一個樹,可以這樣實現(xiàn),printTree 等價于11條print語句

print "   *  " 
print "  ***  " 
print " ***** " 
print "*******" 
print "   *   " 
print "  ***  " 
print " ***** " 
print "*******"
print "   #   "
print "   #   "
print "   #   "

同樣的問題還可以這樣看:printTree等價于先打印兩個樹冠,在打印一個樹干。

printCrown();
printCrown();
printTreeTrunk();

這里的樹冠(crown)和樹干(trunk)就是我們抽象出來的概念。

在上面語義重復(fù)的例子 抽象出的概念是過濾器的概念。

第二步 統(tǒng)一命題

在上面語義重復(fù)的例子 抽象出過濾器的概念后,可以形成這樣一個統(tǒng)一的命題:如果一個原始集合經(jīng)過過濾器過濾,那么會生成一個符合預(yù)期的新集合。

有了過濾器的概念不難定義一個過濾器對象,然后把命題用過濾器對象翻譯出來。

從可讀性的角度看重復(fù)

我們知道可讀性是可維護(hù)性的前提,那么重復(fù)的代碼是怎么影響可讀性的呢?

首先要說一下可讀性的概念。什么是可讀性?可讀性可以定義為理解一段代碼的意圖所需要的時間。時間越短可讀性越好。

而重復(fù)會造成我們看到同一個概念還要繼續(xù)思考一下才明白這是同一個概念。如果重復(fù)的形式是內(nèi)容完全相同那么還好一下,如果是結(jié)構(gòu)重復(fù),甚至是語義重復(fù),那么我們理解代碼段的意圖耗費的時間就更長了,如下圖所示。


所以不管是在產(chǎn)品代碼還是測試代碼中我們都要盡最大努力去掉重復(fù)。

條件測試

待續(xù)...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容