用 Spock 单元测试框架替代 JUnit

本贴最后更新于 2344 天前,其中的信息可能已经天翻地覆

Spock 是一个 Java 及 Groovy 应用的测试框架。它之所以能从众多框架中脱颖而出,是由于它富有表现力的语言。通过 JUnit runner,Spock 能够与大多数 IDE、构建工具及集成测试服务兼容。Spock 的诞生受到了 JUnit, jMock, RSpec, Groovy, Scala, Vulcans 的启发。

Groovy VS Java

此处不做细节上的比较,只提在写单元测试中用到的代码

  1. 类型推断

    orderData.setOrderId(123456L) orderMoney.setInitFactPrice(new BigDecimal("3.2"));
    orderData.orderId = 123456 orderMoney.initFactprice = 3.2
  2. 输出结果

    System.out.println("Hello world");
    println("Hello world")
  3. 创建 List

    List<String> list = new ArrayList<>(); list.add("test1"); list.add("test2"); // 或使用guava List<String> list = Lists.newArrayList("test1","test2"); OrderData odtest1 = new OrderData(); odtest1.setOrderId(123456L); odtest1.setStoreId(123L); OrderData odtest2 = new OrderData(); ... List<OrderData> orderDataList = Lists.newArrayList(); orderDataList.add(odtest1); orderDataList.add(odtest2);
    def list = ["test1","test2"] def orderDataList = [new OrderData(orderId:123456,storeId:123), new OrderData(orderId:123456,storeId:234) ] // 或 orderDataList << new OrderData(orderId:123456,storeId:123) orderDataList << new OrderData(orderId:123456,storeId:124)
  4. 对象比较

    odtest1.getOrderId() == odtest2.getOrderId(); odtest1.getInitFactPrice().compareTo(odtest2.getInitFactPrice()) == 0; //不适用java 8 提供的Stream方法下,判断数组的步骤要更多,如size比较,对应对象或值比较,此处意会即好 for(int i=0;i<list1.size;i++){ list1.get(i).equals(list2.get(i)) }
    odtest1 == odtest2 test1 == test2

更简洁的书写语法,能够让你在对测试有限的热情里写出更多的测试用例

Get Started With Spock

import spock.lang.* class MyFirstSpecification extends Specification { // fields def coll = new Collaborator() @Shared res = new VeryExpensiveResource() // fixture methods def setup() {} // run before every feature method def cleanup() {} // run after every feature method def setupSpec() {} // run before the first feature method def cleanupSpec() {} // run after the last feature method // feature methods def "pushing an element on the stack"() { // blocks go here } // helper methods def testHelper(){ } }

blocks

setup -> 测试准备 clean -> 测试收尾 where -> 循环遍历 when/then : 给定……则满足…… expect:应满足……

Spock VS JUnit

简单的单元测试,测试代码的差异主要在 Java 和 Groovy 的语法差异上,而参数化的单元测试,能够明显的感受到两个测试框架的不同,故此处以参数化测试为例:

// 24 lines @RunWith(Parameterized.class) public class MyTest { private String name; private String family; public MyTest(String name,String family) { super(); this.name = name; this.family = family; } @Parameterized.Parameters public static Collection input() { return Arrays.asList(new Object[][]{ {"Zephyr","Jung"}, {"Y","Z"} }); } @Test public void test(){ System.out.println(name+" "+family); } }
// 10 lines @Unroll("#name #family") class MyTest2 extends Specification { def "test"() { expect: println(name + " " + family) where: name | family "zephyr" | "Jung" "Y" | "Z" } }

这个单元测试中的参数是简单的字符串,我们可以看到,使用 jUnit 来实现参数化的单元测试,写法要比 Spock 更为复杂,当参数是对象时,又会附加上 Java 代码的复杂性,大量的时间用在了模板性质的代码上。

通过 @Unroll 注解,能够将每一个参数作为标题展现在测试结果中

在 SpringBoot 项目中添加 Spock 测试

<dependency> <groupId>org.spockframework</groupId> <artifactId>spock-spring</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
@SpringBootTest @ContextConfiguration(classes = Application.class) class MyTest extends Specification { @Autowired private TicketCenter ticketCenter @Autowired private Train train def "testSpring"() { when: Ticket ticket = ticketCenter.getTicket(new Path(start, end, date)) train.setTicket(ticket) train.travel() then: true where: start | end | date "zhengzhou" | "shanghai" | new Date() "shanghai" | "zhengzhou" | new Date() } }

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...