编写java测试代码的常见场景汇总

本文分享了四个实用的测试技巧:访问私有方法和属性、mock构造器、mock私有属性及校验函数执行情况,帮助编写高效可靠的测试代码。

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


前言:想编写零缺陷的代码,编写测试代码很关键。测试代码的有效性和可靠性也是非常重要的,因此我在最近编写了一点点测试代码之后汇总了“亿”点点的实用技巧。

一、如何访问到类的私有方法或属性

1.1如果类可以构造实例

假设我们有个类Student有私有方法和私有成员变量如下:

class Student{
    private String hobby;
    private String readBook(String book){
     return "happiness";
   }
}

那么,怎样在单元测试代码中通过jmock方便地访问到它们呢?大家第一想到的是使用反射来访问到它们:

私有方法的还有如下的方法:

Method method= Student.class.getDeclaredMethod("readBook",String.class);
method.setAccessible(true);
method.invoke(student, "aBook");
 

补充说明:

  • 如果以上测试的函数参数非具体的对象如String,为父类的List/Map等,我们只需要传入List.class/Map.class即可;
  • 记得getClass()跟XX.class是不一样,记得不要用错了。

除了直接使用反射,还可以使用
Deencapsulation这样优雅去调用(可以更加方便地获取返回值而且无需处理异常捕获,并进行Assert判定)

 
import mockit.Deencapsulation;
 
Student student = new Student();
//其中,“EnglishBook”是传入给readBook()方法的参数,gains是readBook()方法的返回值。
String hobby = Deencapsulation.invoke(student, "hobby");
String gains =Deencapsulation.getField(student, "readBook", "EnglishBook");
Assert.assertEquals("happiness", gains);

1.2如果类没法实例化的情况

class Computer{
     private Computer(){
    )
     private static String surf(String book){
     return "happiness";
)

这种情况也可以使用反射和Deencapsulation进行获取私有方法

Method functionName=AUtil.class.getDeclaredMethod("functionName", String.class, String.class);
functionName.setAccessible(true);
functionName.invoke(AUtil.class,"id","name");//没有正常获取返回值
String gain = Deencapsulation.invoke(Computer.class, "surf", "book");
Assert.assertEquals("happiness", gains);

二、如何mock类的构造器

首先为什么要mock类的构造器呢?由于有些业务场景下类的构造器比较复杂没那么好构造时,就非常需要必要将构造器mock掉
方法如下:

new MockUp<NeedToMockClass>{
    @Mock
    public void $init(){
 
    }
 
    @Mock
    public coid $init(String[] args){
 
    }
}

接下来,再列举实际的场景
现有需要mock的对象如下:
mock的场景如下:编写测试代码的时候需要聚焦到函数generateResBeans的代码段1和2,Resolver这个对象及其函数build是我们不关注的(在其他的测试类中覆盖),需要将其构造器mock掉

public List<ResBean> generateResBeans(Model model){
        //...code segment 1
        Resolver resolver= new Resolver(model);
        List<Res> resList = resolver.build();
       //...code segment 2
}

因此在测试代码使用

public void should_success_when_build_successfully() throws Exception {
    new MockUp<Resolver>(){
        @Mock
        public void $init(Model model){
            this.model = model;
        }   
        @Mock
        public List<Res> build(){
            return new ArrayLIst<>();
        }
    }
 
    Assert.assertTrue(generateResBeans(new Model("model")).isEmpty());
}

三、如何mock类的私有属性

3.1如果类属性为非static

使用Whitebox.setlnternalState()对需要mock 的类对属性进行处理, 现有需要mock的类对象如下,其中需要mock调用其属性logger

public class Impl{
     private MyLog logger = AppLog.getLogger();
     public MyLog logger1 = AppLog.getLogger();
)

测试代码如下:

import org.mockito.internal.util.reflection.Whitebox;
 
OssLog osslog = MOckito.mock(OssLog.class);
Impl impl = new Impl();
Whitebox.setInternalState(impl, "logger", ossLog);
Whitebox.setInternalState(impl, "logger1", ossLog);

impl.function(context,null;//验证function会不会打印
Mockito.verify(ossLog,Mockito.never()).error(anyString()));

3.2如果类属性为static

这种没有直接使用Whitebox.setlnternalState()去设置,用法如下:

static void setFinalStatic(Field field, Object newValue) throws Exception{
    field.setAccessible(true);//remove final moidfer from field
    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(field, field.getModifiers() &~Modifier.FINAL);
    field.set(null, newValue);
}

// 如果该属性为非final,则使用如下方法
static void setStatic(Field field, Object newValue) throws Exception{
    field.setAccessible(true);
    field.set(null, newValue);
}

现有需要mock的类对象如下,其中需要mock调用其属性logger

public class Impl{
     private static final MyLog logger = AppLog.getLogger();
)

测试代码如下:

import static org.mockito.Matchers.anyString;
 
OssLog ossLog=Mockito.mock(OssLog.class);
Impl impl =new Impl0);
setFinalStatic(Impl.class.getDeclaredField("logger"), ossLog);
 
impl.function(context,null;//验证function会不会打印
Mockito.verify(ossLog,Mockito.never()).error(anyString()));

四 verify校验函数是否执行

4.1如果函数为非静态的而且类对象可mock

先mock对象,然后进行mock对象的执行

JobState mock=Mockito.mock(JobState.class);
mock.setState(state);//执行业务代码
Mockito.verify(mock,times(1)).setState(state);
Mockito.verify(mock,never().setState(state);

Mockito.verify 的其他用法:
https://blog.csdn.net/blueZhangFun/article/details/103665393

4.2如果函数为非静态

Mockito很强大,但是它不支持静态方法.所以,就用Powermock了。

(以上内容为DreamKite本人原创,转载请附上原文链接)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dream_Kite

你的鼓励,是我不断创作的动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值