Java几种常用的断言风格你怎么选?

2 篇文章 0 订阅
1 篇文章 0 订阅

日常工作中,不管你是写Unit Test,还是采用TDD的编程方式进行开发,都会遇到断言。而断言的风格常见的会有Assert、BDD风格,对于这些常见的断言风格你怎么选择呢?

01 Assert风格

JUnit中提供了这样的assert断言风格,例如:

@Test
    void should_be_unlocked_when_insert_coin_given_a_entrance_machine_with_locked_state() {
        EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.LOCKED);

        String result = entranceMachine.execute(Action.INSERT_COIN);

        assertEquals("opened", result);
        assertEquals(EntranceMachineState, entranceMachineState.UNLOCKED);
    }

Hamcrest和AssertJ都提供了assertThat()这样风格的断言,例如:

AssertJ提供的assertThat()的断言语法

@Test
    void should_be_unlocked_when_insert_coin_given_a_entrance_machine_with_locked_state() {
        EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.LOCKED);

        String result = entranceMachine.execute(Action.INSERT_COIN);

        assertThat(result).isEqualsTo("opened");
        assertThat(EntranceMachineState).isEqualsTo(entranceMachineState.UNLOCKED);
    }

Hamcrest提供的assertThat()断言语法

@Test
    void should_be_unlocked_when_insert_coin_given_a_entrance_machine_with_locked_state() {
        EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.LOCKED);

        String result = entranceMachine.execute(Action.INSERT_COIN);

        assertThat(result, is("opened"));
        assertThat(EntranceMachineState, is(entranceMachineState.UNLOCKED));
    }

对比上面三种断言语法,因为场景简单,所以结果差异并不是很大。对于我个人更加偏向于使用AssertJ提供的断言风格。因为这种风格避免JUnit提供的断言中经常遇到的问题,expected在前还是actural在前的问题。相比于Hamcrest的断言风格,在日常工作中综合对比发现AssertJ的更加清晰,毕竟AssertJ中assertThat只需要接收一个参数,而不用关注括号是否对齐的问题。

日常工作中如果使用TDD,且场景适当(例如上面例子),那么Hamcreate和AssertJ的差别不是很大。JUnit5默认提供了Hamcreate的断言,不需要额外的再引入其他依赖。

02 BDD风格

代码的可读性越来越收到开发者的重视。测试代码的可读性同样重要,为了让测试代码结构清晰,便于业务逻辑变动时能快读读懂测试的上下文,很多开发团队约定了BDD的风格来组织测试代码。其中包含两部分的约定:测试方法名的约定,测试代码段落的约定。

例如前面的例子:

    @Test
    void should_be_unlocked_when_insert_coin_given_a_entrance_machine_with_locked_state() {
      ...
    }

虽然方法名很长,但是通过方法名我们能够快速知道测试类中有哪些测试,通过方法名我们能够清晰的当前测试的上下文,在测什么,期望的结果什么。通过方法名而不是通过比方法名长很多的代码段来获取测试在测什么的信息,毕竟阅读代码时间和修改代码时间可能是10:1,甚至20:1。所以团队约定BDD的风格组织在后续修改代码时,是受益良多的。

当需要也带具体的测试代码的时候,团队发现按照BDD这种三段式的风格来组织代码受益良多。例如:

@Test
    void should_be_unlocked_when_insert_coin_given_a_entrance_machine_with_locked_state() {
        EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.LOCKED);

        String result = entranceMachine.execute(Action.INSERT_COIN);

        assertThat(result).isEqualsTo("opened");
        assertThat(EntranceMachineState).isEqualsTo(entranceMachineState.UNLOCKED);
    }

我们可以清晰的知道哪行代码在描述上下文,哪几行代码在描述测试意图,哪几行代码在描述测试结果验证。

BDD的风格能够帮助团队将测试代码维护的较为清晰。AssertJ提供了BDD风格的断言方式。使用then()语法。例如:

@Test
    void should_be_unlocked_when_insert_coin_given_a_entrance_machine_with_locked_state() {
        EntranceMachine entranceMachine = new EntranceMachine(EntranceMachineState.LOCKED);

        String result = entranceMachine.execute(Action.INSERT_COIN);

        then(result).isEqualsTo("opened");
        then(EntranceMachineState).isEqualsTo(entranceMachineState.UNLOCKED);
    }

断言变化不大。但是真正仔细读的时候,会发现使用then()还是简单那么一点点的。

我们常用的Mock工具Mockito,也提供了BDD风格的断言:then(), should(), and()。

import static org.mockito.BDDMockito.then;
import static org.assertj.core.api.BDDAssertions.and;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;

@SuppressWarnings("static-access")
@Test
public void bdd_assertions_with_bdd_mockito() {
  Person person = mock(Person.class)
  person.ride(bike);

  person.ride(bike);

  then(person).should(times(2)).ride(bike);
  and.then(person.hasBike()).isTrue();
}

所以日常开发中,我会首先选择then(),其次会选择assertThat()。

关于BDD风格的断言在Mockito中的介绍:BDD Style Verification

除了以上两种断言风格,流式断言让代码更清晰,断言重复内容更少

当我们需要为某个结果测试多个测试点时,如果为每个测试点都组织一次相同的上下文,那么重复代码太多。带来的价值就是那么一点点区别,所以在测试力度上我们可以根据经验来在开发工程中动态调整。

下面据一个例子,当我们需要验证有一个查询方法返回的List的结果时,不单单要验证List中元素的数量,还要验证元素是否时期望的顺序。那么流式写法会缩减一部分重复的断言代码。


then(users).hasSize(3)
           .containsExactlyInAnyOrder(
               firstUser,
               secondUser,
               thirdUser);

上面是日常工作中经常使用到的断言技巧,你的怎么选择的呢?那种风格无所谓能工作就行?

参考

### 回答1: 硬件描述语言(HDL)设计中,常用的描述方式有:结构化硬件描述语言(Structured HDL)、调制解调器描述语言(Modeling Language)、状态机描述语言(State Machine Description Language)和非结构化硬件描述语言(Unstructured HDL)。 ### 回答2: 在HDL(硬件描述语言)设计中,常用几种描述方式包括: 1. Verilog:Verilog是一种高级硬件描述语言,适用于电子系统级设计和数字电路级设计。Verilog描述方式类似于C语言,它通过模块(module)的组合实现电路的功能。Verilog可以描述时序逻辑和组合逻辑,广泛用于数字电路设计和验证。 2. VHDL:VHDL(VHSIC硬件描述语言)是一种可编程的硬件描述语言,适用于数字电路、模拟电路和混合电路的设计。VHDL的描述方式比较详细和严谨,可以描述电路的结构、行为和时序。VHDL具有强大的仿真和综合功能,广泛应用于电子系统级设计和数字电路级设计。 3. SystemVerilog:SystemVerilog是Verilog的扩展版本,引入了一些新的特性和语法,使得它更适用于硬件设计和验证。SystemVerilog支持面向对象的设计,可以描述复杂的硬件系统。它还提供了强大的断言和约束来验证设计的正确性。 4. C/C++:在一些高级综合工具中,可以使用C/C++语言进行HDL设计。C/C++可以更方便地描述算法和控制逻辑,对于复杂的处理器设计和通信协议实现有很大优势。C/C++描述方式适用于软硬件协同设计和嵌入式系统的开发。 这些描述方式可以根据设计需求和开发工具的支持来择。每种描述方式都有自己的特点和适用范围,设计工程师可以根据具体情况择最适合的描述方式来完成HDL设计。 ### 回答3: HDL(硬件描述语言)设计是一种用于描述和设计数字电路的方法。常用几种HDL描述方式包括: 1.行为级描述方式:行为级描述方式是一种较高级别的描述方式,它描述了数字电路的功能和操作。在行为级描述中,不考虑电路的内部细节和逻辑结构,主要关注电路的输入、输出以及它们之间的关系。常见的行为级描述语言包括VHDL和Verilog。 2.结构级描述方式:结构级描述方式是一种较低级别的描述方式,它描述了数字电路的具体的逻辑结构和组件连接关系。在结构级描述中,使用逻辑门、触发器、多路择器等基本元件来组合和连接构成电路。常见的结构级描述语言包括VHDL和Verilog。 3.数据流描述方式:数据流描述方式是一种中级描述方式,它描述了数字电路中数据的流动和操作。在数据流描述中,通过指定数据的进出口和操作函数,来描述电路中数据的流动路径。常见的数据流描述语言包括VHDL和Verilog。 4.寄存器传输级描述方式:寄存器传输级描述方式是一种具有时序特性的描述方式,它描述了数字电路中的时钟、寄存器和数据传输。在寄存器传输级描述中,通过描述时钟控制和寄存器的输入输出关系,来描述和分析电路的时序行为。常见的寄存器传输级描述语言包括VHDL和Verilog。 总之,HDL设计中常用几种描述方式包括行为级描述、结构级描述、数据流描述和寄存器传输级描述。使用不同的描述方式,可以从不同的角度来描述和设计数字电路,以满足不同的设计需求和要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值