使用Groovy 编写Java 代码的测试

作者: 沪上最强亚巴顿 | 来源:发表于2017-01-14 13:44 被阅读2895次

Groovy

Groovy 是一种带有可选类型系统的动态语言. 借助Groovy语言, 可以在需要强类型时得到类型系统的静态检查保障, 而在需要灵活性时, 享受到Duck Typing 的便利性.

在编写测试代码方面上, Groovy 的优势主要体现在optional syntax rulepower assertion statement 两个方面上.

  • optional syntax rule. 在Java 中强制的部分语法规则, 如分号, 变量类型, 访问修饰符,在Groovy 中都是可选的.

    • 对测试的影响: 跳过Java private 修饰符的封装性, 测试类可以读取被测试类的内部状态.
  • power assertion statement. 提供了强大的多样化的assert.

    • 主要优势: 比Java 更有可读性, 且能够清晰地展示验证失败时的结果.

    • 例如, 在Java 中的断言语句:

      Assert.isTrue(foo.bar.equals("hello"));

      在Goovy 中可以写成这样:

      assert foo.bar == "hello".

      更进一步, 使用Spock 测试框架, 可以进一步简写为:

      expect:
      foo.bar == "hello"
      

Spock

Spock 集成了Junit, JMock 和RSpec 等测试框架的优势, 使开发者能够使用BDD DSL 语言进行测试代码的编写.

它完全兼容Junit, 同时不需要依赖任何的Mock 框架(如Mockito).

关于Spock 技术的更多信息, 请参考Spock Primer.

在这里, 给出Spock 与JUnit 的术语对比表. 以增加大家的直观理解.

Spock JUnit
Specification Test class
setup() @Before
cleanup() @After
setupSpec() @BeforeClass
cleanupSpec() @AfterClass
Feature Test
Feature method Test method
Data-driven feature Theory
Condition Assertion
Exception condition @Test(expected=…)
Interaction Mock expectation (e.g. in Mockito)

实践

在Intellij IDEA 作为IDE, 并使用Gradle 作为工程构建工具.

环境准备

  • 在Intellij 中安装gmavnen intelliJ pluginspock plugin 两个插件.

  • build.gradle 中应用Groovy 插件:

    apply plugin: 'groovy'

    该插件会在编译期间, 编译src/main/groovysrc/test/groovy 目录下的Groovy 源文件.

  • build.gradle 中添加Spock 的依赖:

    testCompile(
        ...
        "org.spockframework:spock-core:$spockCoreVersion",
    )
    

对Java 单元测试的改造

  • 首先, 这是遗留的使用Java 语言编写的单元测试代码:

    @RunWith(SpringJUnit4ClassRunner.class)
    public class DefaultGatewayInterruptServiceTest {
    
        @Mock
        private GatewayInterruptMapper gatewayInterruptMapper;
    
        @Mock
        private CompanyManageService companyManageService;
    
        @Mock
        private AreaManageService areaManageService;
    
        @Mock
        private RolePermissionManageService rolePermissionManageService;
    
        @InjectMocks
        DefaultGatewayInterruptService service;
    
        @Test
        public void should_return_gateway_interruptions() {
            List<GatewayInterrupt> interrupts = Lists.newArrayList();
            GatewayInterrupt interrupt1 = new GatewayInterrupt();
            interrupt1.setCompanyId(1L);
            interrupt1.setDistrictId(11L);
            interrupt1.setSiteId(111L);
            interrupt1.setGatewayId(1111L);
            interrupt1.setInterruptTime(new GregorianCalendar(2000, 1, 1).getTime());
            interrupt1.setRecoveryTime(new GregorianCalendar(2000, 1, 2).getTime());
            interrupt1.setStatus(false);
            interrupts.add(interrupt1);
    
            GatewayInterrupt interrupt2 = new GatewayInterrupt();
            interrupt2.setCompanyId(1L);
            interrupt2.setDistrictId(11L);
            interrupt2.setSiteId(111L);
            interrupt2.setGatewayId(2222L);
            interrupt2.setInterruptTime(new GregorianCalendar(2000, 1, 1).getTime());
            interrupt2.setStatus(true);
            interrupts.add(interrupt2);
    
            when(gatewayInterruptMapper.getAll()).thenReturn(interrupts);
    
            HashMap<Long, Company> companyHashMap = Maps.newHashMap();
            Company company = new Company();
            company.setName("compnay1");
            companyHashMap.put(1L, company);
            when(companyManageService.getCachedReadOnlyCompanyMap()).thenReturn(companyHashMap);
    
            HashMap<Long, District> districtHashMap = Maps.newHashMap();
            District district = new District();
            district.setName("district1");
            districtHashMap.put(11L, district);
            when(areaManageService.getCachedReadOnlyDistrictMap()).thenReturn(districtHashMap);
    
            HashMap<Long, Site> siteHashMap = Maps.newHashMap();
            Site site = new Site();
            site.setName("site1");
            siteHashMap.put(111L, site);
            when(areaManageService.getCachedReadOnlySiteMap()).thenReturn(siteHashMap);
    
            HashMap<Long, Gateway> gatewayHashMap = Maps.newHashMap();
            Gateway gateway1 = new Gateway();
            gateway1.setId(1111L);
            gateway1.setName("gateway1");
            Gateway gateway2 = new Gateway();
            gateway2.setId(2222L);
            gateway2.setName("gateway2");
            gatewayHashMap.put(1111L, gateway1);
            gatewayHashMap.put(2222L, gateway2);
            when(areaManageService.getCachedReadOnlyGatewayMap()).thenReturn(gatewayHashMap);
    
            List<User> users = Lists.newArrayList();
            User user = new User();
            user.setName("user1");
            users.add(user);
            when(rolePermissionManageService.getManagerOfSite(any())).thenReturn(users);
    
            List<GatewayInterruptDTO> interruptions = service.getGatewayInterruptions();
            assertThat(interruptions.size(), is(2));
        }
    }
    
  • 使用Groovy 进行改造后的代码如下:

    class DefaultGatewayInterruptServiceSpec extends Specification {
        def gatewayInterruptMapper = Mock(GatewayInterruptMapper)
        def companyManageService = Mock(CompanyManageService)
        def areaManageService = Mock(AreaManageService)
        def rolePermissionManageService = Mock(RolePermissionManageService)
    
        def service = new DefaultGatewayInterruptService
                (gatewayInterruptMapper, companyManageService, areaManageService, rolePermissionManageService)
    
        def "should return gateway interruptions"() {
            given:
            def interrupt1 = new GatewayInterrupt(
                    companyId: 1L, districtId: 11L, siteId: 111L, gatewayId: 1111L,
                    interruptTime: new GregorianCalendar(2000, 1, 1).getTime(),
                    recoveryTime: new GregorianCalendar(2000, 1, 2).getTime(),
                    status: false
            )
            def interrupt2 = new GatewayInterrupt(
                    companyId: 1L, districtId: 11L, siteId: 111L, gatewayId: 2222L,
                    interruptTime: new GregorianCalendar(2000, 1, 1).getTime(),
                    status: true
            )
    
            when:
            def interruptions = service.getGatewayInterruptions()
    
            then:
            gatewayInterruptMapper.getAll() >> [interrupt1, interrupt2]
            companyManageService.getCachedReadOnlyCompanyMap() >> [1L: new Company(name: "company1")]
            areaManageService.getCachedReadOnlyDistrictMap() >> [11L: new District(name: "district1")]
            areaManageService.getCachedReadOnlySiteMap() >> [111L: new Site(name: "site1")]
            areaManageService.getCachedReadOnlyGatewayMap() >> [1111L: new Gateway(id: 1111L, name: "gateway1"), 2222L: new Gateway(id: 2222L, name: "gateway2")]
            rolePermissionManageService.getManagerOfSite(_ as Site) >> [new User(name: "user1")]
    
            interruptions.size() == 2
        }
    }
    

    这段代码中体现了Groovy 的强大便利:

    • 构造器中能够给字段赋值.

      def interrupt1 = new GatewayInterrupt(
                      companyId: 1L, districtId: 11L, siteId: 111L, gatewayId: 1111L,
                      interruptTime: new GregorianCalendar(2000, 1, 1).getTime(),
                      recoveryTime: new GregorianCalendar(2000, 1, 2).getTime(),
                      status: false
              )
      
    • List 字面量和Map 字面量:

      [interrupt1, interrupt2]
      [11L: new District(name: "district1")]
      
    • 简洁的Mock 写法:

      then:
      gatewayInterruptMapper.getAll() >> [interrupt1, interrupt2]
      

相关文章

  • 使用Groovy 编写Java 代码的测试

    Groovy Groovy 是一种带有可选类型系统的动态语言. 借助Groovy语言, 可以在需要强类型时得到类型...

  • 用groovy编写springboot单元测试

    用groovy编写springboot单元测试,且java和groovy混合编程 源代码下载地址https://g...

  • Gradle spring boot 2.1.0 Java 和

    groovy编写静态工具类方法 java 写业务代码可以 调用到 groovy目录下 的静态工具类方法 目录结构:...

  • 自动化测试

    概述 编写的测试代码就是 Java 代码 运行要遵守 Java 的语法和 JVM 的规定 测试类型 手工测试 单元...

  • Responsive测试

    Responsive测试 如何使用Galen进行响应式测试 使用Javascript编写测试代码 完整代码:htt...

  • 使用JMH做Java微基准测试

    摘要:# 使用JMH做Java微基准测试 在使用Java编程过程中,我们对于一些代码调用的细节有多种编写方式,但是...

  • junit学习小结

    junit 什么是junit这是一个Java测试框架,可以通过它来编写测试案例,对写好的代码进行测试 如何使用在j...

  • 使用JMH做Java微基准测试

    使用JMH做Java微基准测试 在使用Java编程过程中,我们对于一些代码调用的细节有多种编写方式,但是不确定它们...

  • 使用Groovy开发之新特性

    一个java程序员刚开始使用Groovy的时候,不可避免的满脑子想的都是java,当熟悉Groovy后就会代码会逐...

  • Groovy简介与使用

    简介使用应用 Groovy语法特性(相比于Java) Groovy与Java项目集成使用GroovyShellGr...

网友评论

    本文标题:使用Groovy 编写Java 代码的测试

    本文链接:https://www.haomeiwen.com/subject/pypebttx.html