日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢(xún)客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

為什么你的測(cè)試應(yīng)該只驗(yàn)證可觀察的行為,而不是實(shí)現(xiàn)細(xì)節(jié)

在 Java 中斷言?xún)?nèi)部行為

 

在本文中,我們將考慮我們的測(cè)試到底應(yīng)該(不)驗(yàn)證什么以防止誤報(bào),以及為什么有時(shí)越少越好。為了更好地理解這個(gè)主題,我們將仔細(xì)研究脆性測(cè)試和可觀察行為的定義,以便我們能夠檢測(cè)設(shè)計(jì)不良的測(cè)試并使其抵抗重構(gòu)。

讓我們開(kāi)始吧!

 

當(dāng)您的測(cè)試想知道太多時(shí)

回到過(guò)去,在我深入研究自動(dòng)化測(cè)試這個(gè)主題之前,它已經(jīng)發(fā)生在我身上很多次了。究竟是什么?好吧,以防萬(wàn)一,我想確保我的測(cè)試驗(yàn)證了比必要的更多的東西。我曾經(jīng)相信我的測(cè)試包含的斷言和類(lèi)似的陳述越多,它們帶來(lái)的價(jià)值就越大。

雖然上述方法看起來(lái)很合理,但從長(zhǎng)遠(yuǎn)來(lái)看,選擇它會(huì)讓開(kāi)發(fā)人員的生活變得困難。當(dāng)我自己的測(cè)試讓我不得不比我預(yù)期的更頻繁地回到他們身邊時(shí),我很難發(fā)現(xiàn)這一點(diǎn)。一個(gè)理由?事實(shí)證明,這些測(cè)試與實(shí)現(xiàn)細(xì)節(jié)有關(guān),而不是可觀察到的行為,因此,在重構(gòu)時(shí),即使功能仍然可以正常工作,它們也會(huì)失敗。

 

脆弱的測(cè)試? 可觀察的行為? 實(shí)施細(xì)則?

在我們進(jìn)一步討論之前,讓我們先定義一下這些神秘短語(yǔ)背后的含義,因?yàn)樗鼈儗?duì)于理解如何編寫(xiě)為我們的項(xiàng)目增加真正價(jià)值而不是不必要的包袱的良好測(cè)試至關(guān)重要。

 

  • 它們無(wú)法承受重構(gòu),無(wú)論底層功能是否損壞,它們都會(huì)變紅

換句話說(shuō),重構(gòu)后的功能仍然可以產(chǎn)生正確的結(jié)果,但與此同時(shí),如果他們檢查某些東西是如何工作的,而不是檢查可觀察到的行為是什么,你的測(cè)試可能會(huì)失敗。

 

  • 要使一段代碼成為系統(tǒng)可觀察行為的一部分,它必須執(zhí)行以下操作之一:
  • 公開(kāi)幫助客戶(hù)實(shí)現(xiàn)其目標(biāo)之一的操作。 操作是一種執(zhí)行計(jì)算或產(chǎn)生副作用或兩者兼而有之的方法。
  • 暴露一種可以幫助客戶(hù)實(shí)現(xiàn)其目標(biāo)之一的狀態(tài)。 狀態(tài)是系統(tǒng)的當(dāng)前狀態(tài)。
  • 任何不做這兩件事的代碼都是實(shí)現(xiàn)細(xì)節(jié)。

因此,當(dāng)您在開(kāi)發(fā)新功能時(shí),請(qǐng)考慮調(diào)用您的代碼的客戶(hù)端的真正目標(biāo)是什么(客戶(hù)端代碼期望從我們的解決方案中獲得什么行為,或者您的功能應(yīng)該涵蓋哪些業(yè)務(wù)案例),然后忘記 暫時(shí)您想如何開(kāi)發(fā)該功能(實(shí)現(xiàn)細(xì)節(jié))。

這種方法應(yīng)該讓您在可觀察的行為和實(shí)現(xiàn)細(xì)節(jié)之間有一個(gè)更清晰的區(qū)別。

 

案例研究:排行榜

讓我們仔細(xì)看看下面用 JAVA 編寫(xiě)的示例:

  • 我們正在為一款游戲開(kāi)發(fā)排行榜,我們稱(chēng)這款游戲?yàn)?ldquo;Chase and Race”
  • 我們希望我們的排行榜根據(jù)得分返回最佳玩家

Player 類(lèi)負(fù)責(zé)保存玩家的姓名和分?jǐn)?shù)。 分?jǐn)?shù)通過(guò) Player#updateScore 函數(shù)更新。

Leaderboard 類(lèi)允許我們通過(guò) Leaderboard#addPlayer 函數(shù)將玩家添加到排行榜的列表中,并通過(guò) Leaderboard#getBestPlayer 檢索游戲中最好的玩家。

在 LeaderboardTesttest 類(lèi)中,我們正在檢查 Leaderboard#getBestPlayer 方法是否能夠返回得分最高的玩家:

package chaseandrace.player;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Leaderboard {
  List<Player> players;

  public Leaderboard() {
    players = new ArrayList<>();
  }

  public void addPlayer(Player player) {
    this.players.add(player);
  }
  
  public Player getBestPlayer() {
    return players.stream()
        .max(Comparator.comparing(Player::getScore))
        .orElse(null);
  }
}
package chaseandrace.player;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

public class LeaderboardTest {
  @Test
  void getPlayerWithHighestScore() {
    var playerOne = new Player("I don't know what I'm doing here");
    var playerTwo = new Player("Chase me");
    var playerThree = new Player("Okie Dokie");
    
    playerOne.updateScore(50);
    playerTwo.updateScore(90);
    playerThree.updateScore(85);
    
    var board = new Leaderboard();
    board.addPlayer(playerOne);
    board.addPlayer(playerTwo);
    board.addPlayer(playerThree);

    var bestPlayer = board.getBestPlayer();
    assertEquals(playerTwo, bestPlayer);
    assertEquals(bestPlayer, board.players.get(1));
  }
}
package chaseandrace.player;

public class Player {
  private String name;
  private int score;
  
  public Player(String name) {
    this.name = name;
  }
  
  public int getScore() {
    return score;
  }

  public void updateScore(int points) {
    score += points;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
}
在 Java 中斷言?xún)?nèi)部行為

 

到目前為止,一切都很好——如您所見(jiàn),測(cè)試報(bào)告是綠色的。

 

后來(lái),我們決定重構(gòu) Leaderboard 類(lèi)的內(nèi)部結(jié)構(gòu),因此每當(dāng)我們向其中添加新玩家時(shí),它都會(huì)按降序?qū)ν婕伊斜磉M(jìn)行排序:

package chaseandrace.player;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Leaderboard {
  List<Player> players;

  public Leaderboard() {
    players = new ArrayList<>();
  }

  public void addPlayer(Player player) {
    this.players.add(player);
    this.players.sort(Comparator.comparing(Player::getScore, Comparator.reverseorder()));
  }
  
  public Player getBestPlayer() {
    if (players.isEmpty()) {
      return null;
    }
    
    return players.get(0);
  }
}
package chaseandrace.player;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

public class LeaderboardTest {
  @Test
  void getPlayerWithHighestScore() {
    var playerOne = new Player("I don't know what I'm doing here");
    var playerTwo = new Player("Chase me");
    var playerThree = new Player("Okie Dokie");
    
    playerOne.updateScore(50);
    playerTwo.updateScore(90);
    playerThree.updateScore(85);
    
    var board = new Leaderboard();
    board.addPlayer(playerOne);
    board.addPlayer(playerTwo);
    board.addPlayer(playerThree);

    var bestPlayer = board.getBestPlayer();
    assertEquals(playerTwo, bestPlayer);
    assertEquals(bestPlayer, board.players.get(1));
  }
}
package chaseandrace.player;

public class Player {
  private String name;
  private int score;
  
  public Player(String name) {
    this.name = name;
  }
  
  public int getScore() {
    return score;
  }

  public void updateScore(int points) {
    score += points;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
  
  @Override
  public String toString() {
    return name;
  }
}
在 Java 中斷言?xún)?nèi)部行為

 

讓我們省略關(guān)于是否需要此更改的討論——我想向您展示的是更改實(shí)現(xiàn)細(xì)節(jié)如何影響現(xiàn)有測(cè)試。

如您所見(jiàn),測(cè)試報(bào)告變?yōu)榧t色,但可觀察到的行為保持不變——Leaderboard#getBestPlayer 函數(shù)仍然正常工作,它返回得分最高的玩家。

如何解決這個(gè)問(wèn)題? 如果在重構(gòu)代碼庫(kù)的情況下,一次編寫(xiě)的測(cè)試不需要我們額外關(guān)注,那將是最好的。 為此,Leaderboard#players 列表應(yīng)該無(wú)法從外部訪問(wèn),因此使用 private 修飾符標(biāo)記這個(gè)集合就足夠了:

package chaseandrace.player;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Leaderboard {
  private List<Player> players;

  public Leaderboard() {
    players = new ArrayList<>();
  }

  public void addPlayer(Player player) {
    this.players.add(player);
    this.players.sort(Comparator.comparing(Player::getScore, Comparator.reverseOrder()));
  }
  
  public Player getBestPlayer() {
    if (players.isEmpty()) {
      return null;
    }
    
    return players.get(0);
  }
}

但是測(cè)試呢? 它現(xiàn)在有一個(gè)編譯錯(cuò)誤:

在 Java 中斷言?xún)?nèi)部行為

 

由于您的測(cè)試應(yīng)該只驗(yàn)證可觀察的行為,我們可以安全地從第 25 行刪除斷言,因?yàn)樗鼨z查實(shí)現(xiàn)細(xì)節(jié),這使得該測(cè)試變得脆弱。

 

結(jié)論

在項(xiàng)目中進(jìn)行脆弱測(cè)試的后果可能非常嚴(yán)重。 例如,這樣的測(cè)試可能會(huì)阻止開(kāi)發(fā)人員重構(gòu)代碼,因?yàn)槔蠈?shí)說(shuō)——當(dāng)你完成重構(gòu)時(shí),這導(dǎo)致了一堆失敗的測(cè)試,這并不一定會(huì)讓你心情愉快。 另一個(gè)可能的后果是,開(kāi)發(fā)人員可以習(xí)慣于發(fā)出錯(cuò)誤警報(bào)的測(cè)試,從而降低他們的整體警覺(jué)性,從而使錯(cuò)誤潛入生產(chǎn)環(huán)境的機(jī)會(huì)增加。

分享到:
標(biāo)簽:Java
用戶(hù)無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定