编写JUnit测试的另一种方法(Jasmine方法)

最近,我为一个小型个人项目编写了很多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测试失败的结果:

oleaster-idea

如果您想知道Oleaster测试在实践中的外观,可以看看Oleaster的测试(这些测试是用Oleaster本身编写的)。 您可以在此处找到GitHub测试目录。

通过评论此帖子或创建GitHub问题,随时添加任何类型的反馈。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值