单元测试框架对比

这篇博客对比了junit + mockito和testng + jmockit两种单元测试及模拟搭配方式。作者发现junit + mockito与spring结合更加紧密,适合业务自动化回归测试,而testng + jmockit虽然功能强大,但与spring集成存在困难,更适合专注于独立、简单的单元测试。根据项目需求,作者认为junit + mockito可能是更好的选择。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单元测试框架对比

主要小试了下junit + mockito 及 testng + jmockit两种ut及mock搭配方式。做下简单对比,当做笔记。
- junit + mockito
- testng + jmockit


junit + mockito

依赖:

            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.junit.version}</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-core</artifactId>
                <version>${mockito-core.version}</version>
            </dependency>

同spring结合,BaseTest类。继承AbstractTransactionalJUnit4SpringContextTests 加入了事务。

import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.springframework.context.ApplicationContextAware;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@ContextConfiguration(locations = { "classpath:spring-test.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
public class BaseTest extends AbstractTransactionalJUnit4SpringContextTests implements ApplicationContextAware {
    @Before
    public void setup() {
        /** Initializes objects annotated with Mockito annotations for given testClass */
        MockitoAnnotations.initMocks(this);
    }
}

test子类。
简单说明:leaseBiz是业务逻辑层,调用leaseService层去查询数据库。

package com.unifirst.biz;

import java.math.BigDecimal;
import java.util.Date;

import javax.annotation.Resource;

import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.springframework.test.util.ReflectionTestUtils;

import com.unifirst.BaseTest;
import com.unifirst.model.po.LeaseRecord;
import com.unifirst.model.ro.LeaseDetailResp;
import com.unifirst.service.LeaseService;

/**
 * Created by unifirst on 2018/3/13.
 */
public class LeaseTest extends BaseTest {
    @Spy
    private LeaseService leaseService;

    @Resource
    @InjectMocks
    private LeaseBiz leaseBiz;

    @Before
    public void init() {
        LeaseRecord leaseRecord = new LeaseRecord();
        leaseRecord.setTotalAmount(BigDecimal.ONE);
        leaseRecord.setEndTime(new Date());
        leaseRecord.setStartTime(new Date());
        leaseRecord.setUid(30030633745056L);
        leaseRecord.setLeaseNumber(317733346556907520L);

        /** 仅仅用spy + InjectMocks,无法成功注入;需要用反射方式注入 */
        ReflectionTestUtils.setField(leaseBiz, "leaseService", leaseService);

        Mockito.when(leaseService.queryDetail(Mockito.anyLong())).thenReturn(leaseRecord);
    }

    @Test
    public void detailTest() {
        LeaseDetailResp detail = leaseBiz.detail(30030633745056L, 317733346556907520L);
        System.out.println(detail);
    }
}

testng + jmockit

依赖

            <dependency>
                <groupId>org.testng</groupId>
                <artifactId>testng</artifactId>
                <version>${testng.version}</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.jmockit</groupId>
                <artifactId>jmockit</artifactId>
                <version>${jmockit.version}</version>
            </dependency>

test类
几处注意的地方:

  1. 无上面与spring结合的BaseTest类
  2. @Tested注解的不是interface,而是具体实现类
  3. 虽然被测试代码仅仅使用到了globalConfigBiz,但其他@Resource引入的service,都需要用@Injectable注入,否则报错:
 java.lang.IllegalStateException: Missing @Injectable for field xxx
  1. 若被test的类有@Value注解,则同service一样要通过@Injectable注入

代码示例如下:

package com.unifirst.biz;

import java.util.List;

import org.testng.annotations.Test;
import org.testng.collections.Lists;

import com.unifirst.biz.impl.FeedBackBizImpl;
import com.unifirst.model.bo.FaultTypes;
import com.unifirst.service.FeedBackService;
import com.unifirst.service.OpLogService;
import com.wormpex.api.json.JsonUtil;

import mockit.Expectations;
import mockit.Injectable;
import mockit.Tested;

/**
 * Created by unifirst on 2018/3/14.
 */
public class FeedBackBizTest {
    @Tested
    private FeedBackBizImpl feedBackBiz;
    @Injectable
    private FeedBackService feedBackService;
    @Injectable
    private OpLogService opLogService;
    @Injectable
    private GlobalConfigBiz globalConfigBiz;

    @Test
    public void faultTypeListsTest() {
        new Expectations() {
            {
                FaultTypes faultTypes = new FaultTypes();
                List<String> types = Lists.newArrayList("t1", "t2");
                faultTypes.setTypes(types);

                globalConfigBiz.query(anyString);
                result = JsonUtil.of(faultTypes);
            }
        };

        List<String> detail = feedBackBiz.faultTypeLists();
        System.out.println(detail);
    }
}

对比

junit vs testng,mockito vs jmockit 网上资料很多,不多介绍。这里只从与spring的结合性来简单对比。

  • junit + mockito 与spring结合性感觉更强,可以充分兼容spring的各种注解,能较完美接近项目启动后实际运行情况。可以用来做一定的业务自动化回归测试,但可能超出了ut的范围
  • testng + jmockit 可能功能更强大,但与spring不易结合,各种注解不好兼容,如上例中直接放弃了在spring中的测试。反过来说,不依赖spring,专注测好一件事情。

UT理念应该是小而简单、保持独立、mock依赖都能正确工作。这应该是jmockit所追求的,所以强调脱离spring的正常工作。
但目前项目中,需要用ut做一部分业务自动化测试,因此可能junit + mockito更适合。

个人浅见,欢迎拍砖。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值