天天看點

junit5_編寫JUnit測試的另一種方法(Jasmine方法)

junit5_編寫JUnit測試的另一種方法(Jasmine方法)

junit5

最近,我為一個小型個人項目編寫了許多Jasmine測試。 我花了一些時間才終于感到正确地完成了測試。 此後,當我切換回JUnit測試時,我總是很難過。 由于某種原因,JUnit測試不再那麼好,我想知道是否有可能以類似于Jasmine的方式編寫JUnit測試。

Jasmine是受RSpec (Ruby BDD測試架構)啟發而流行JavaScript行為驅動開發測試架構。

一個簡單的茉莉花測試如下所示:

describe('AudioPlayer tests', function() {
  var player;

  beforeEach(function() {
    player = new AudioPlayer();
  });
  
  it('should not play any track after initialization', function() {
    expect(player.isPlaying()).toBeFalsy();
  });
  
  ...
});
           

第一行中的describe()函數調用使用Description AudioPlayer tests建立一個新的測試套件。 在測試套件中,我們可以使用it()建立測試(在Jasmine中稱為specs)。 在這裡,我們檢查建立新的AudioPlayer的isPlaying()方法是否傳回false。AudioPlayer執行個體。

用JUnit編寫的相同測試如下所示:

public class AudioPlayerTest {
  private AudioPlayer audioPlayer;

  @Before 
  public void before() {
    audioPlayer = new AudioPlayer();
  }

  @Test
  void notPlayingAfterInitialization() {
    assertFalse(audioPlayer.isPlaying());
  }
  
  ...
}
           

我個人認為Jasmine測試與JUnit版本相比更具可讀性。 在Jasmine中,唯一對測試沒有任何影響的噪音是花括号和function關鍵字。 其他所有内容都包含一些有用的資訊。

在閱讀JUnit測試時,我們可以忽略諸如void,通路修飾符(私有,公共,..),注釋和不相關的方法名稱(如以@Before注釋的方法名稱)之類的關鍵字。 除此之外,以駝峰案例方法名稱編碼的測試描述不太好讀。

除了提高可讀性外,我真的很喜歡Jasmine嵌套測試套件的功能。

讓我們來看一個更長的示例:

describe('AudioPlayers tests', function() {
  var player;

  beforeEach(function() {
    player = new AudioPlayer();
  });
  
  describe('when a track is played', function() {
    var track;
  
    beforeEach(function() {
      track = new Track('foo/bar.mp3')
      player.play(track);
    });
    
    it('is playing a track', function() {
      expect(player.isPlaying()).toBeTruthy();
    });
    
    it('returns the track that is currently played', function() {
      expect(player.getCurrentTrack()).toEqual(track);
    });
  });
  
  ...
});
           

在這裡,我們建立了一個子測試套件,負責測試AudioPlayer播放曲目時的行為。 内部的beforeEach()調用用于為子測試套件内的所有測試設定通用的前提條件。

相反,在JUnit中為多個(但不是全部)測試共享通用的前提條件有時會變得很麻煩。 當然,在測試中複制設定代碼是不好的,是以我們為此建立了額外的方法。 為了在設定方法和測試方法之間共享資料(例如上面示例中的track變量),我們必須使用成員變量(範圍要大得多)。

另外,我們應確定将具有類似前提條件的測試分組在一起,以避免需要閱讀整個測試類以找到特定情況下的所有相關測試。 或者我們可以将事情分成多個較小的類。 但是,然後我們可能必須在這些類之間共享設定代碼……

如果我們檢視Jasmine測試,就會發現該結構是通過調用全局函數(例如describe(),it(),…)并傳遞描述性字元串和匿名函數來定義的。

使用Java 8,我們得到了Lambdas,是以我們可以做同樣的事情嗎?

是的,我們可以在Java 8中編寫如下代碼:

public class AudioPlayerTest {
  private AudioPlayer player;
  
  public AudioPlayerTest() {
    describe("AudioPlayer tests", () -> {
      beforeEach(() -> {
        player = new AudioPlayer();
      });

      it("should not play any track after initialization", () -> {
        expect(player.isPlaying()).toBeFalsy();
      });
    });
  }
}
           

如果我們暫時假設describe(),beforeEach(),it()和Expect()是采用适當參數的靜态導入方法,則至少可以編譯。 但是,我們應該如何進行這種測試?

出于興趣,我嘗試将其與JUnit內建,結果發現這實際上非常簡單(我将在以後進行介紹)。 到目前為止,結果是一個名為Oleaster的小型圖書館。

用Oleaster編寫的測試如下所示:

import static com.mscharhag.oleaster.runner.StaticRunnerSupport.*;
...

@RunWith(OleasterRunner.class)
public class AudioPlayerTest {
  private AudioPlayer player;
  
  {
    describe("AudioPlayer tests", () -> {
      beforeEach(() -> {
        player = new AudioPlayer();
      });
    
      it("should not play any track after initialization", () -> {
        assertFalse(player.isPlaying());
      });
    });
  }
}
           

與前面的示例相比,隻有幾處發生了變化。 在這裡,測試類使用JUnit @RunWith注釋進行注釋。 這告訴JUnit在運作此測試類時使用Oleaster。 通過靜态導入StaticRunnerSupport。*,可以直接通路靜态Oleaster方法,例如describe()或it()。 還要注意,構造函數已由執行個體初始化程式替換,而Jasmine like matcher被标準JUnit斷言替換。

與原始的茉莉花測試相比,實際上有一件事情并不那麼出色。 實際上,在Java中,變量必須有效地最終确定才能在lambda表達式中使用。 這意味着以下代碼段不會編譯:

describe("AudioPlayer tests", () -> {
  AudioPlayer player;
  beforeEach(() -> {
    player = new AudioPlayer();
  });
  ...
});
           

在beforeEach()lambda表達式中對玩家的指派将不會編譯(因為玩家實際上不是最終的)。 在Java中,我們必須在這種情況下使用執行個體字段(如上例所示)。

萬一您擔心要報告:Oleaster僅負責收集和運作測試用例。 整個報告仍由JUnit完成。 是以,Oleaster應該不會對使用JUnit報表的工具和庫造成任何問題。

例如,以下螢幕截圖顯示了IntelliJ IDEA中Oleaster測試失敗的結果:

junit5_編寫JUnit測試的另一種方法(Jasmine方法)
junit5_編寫JUnit測試的另一種方法(Jasmine方法)

如果您想知道Oleaster測試在實踐中的外觀,您可以看看Oleaster的測試(用Oleaster本身編寫)。 您可以在此處找到GitHub測試目錄。

通過評論此文章或建立GitHub問題,随時添加任何類型的回報。

翻譯自: https://www.javacodegeeks.com/2014/07/an-alternative-approach-of-writing-junit-tests-the-jasmine-way.html

junit5