(四)JMockit 的API:@Injectable 与 @Mocked的不同--基础篇

本文介绍@Injectable与@Mocked注解的区别及@Tested与@Injectable的搭配使用。解释了@Injectable如何仅影响类的一个实例,而@Mocked影响所有实例。并通过一个电商网站下单场景的例子展示了@Tested与@Injectable的具体应用。

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

  1. @Injectable 与 @Mocked的不同
import mockit.Injectable;
import mockit.Mocked;
import org.junit.Assert;
import org.junit.Test;

import java.util.Locale;

//@Mocked 与@Injectable的不同
public class MockedAndInjectable {

    @Test
    public  void testMocked(@Mocked Locale locale){
        //静态方法不起作用了,返回了null
        Assert.assertTrue(Locale.getDefault() == null);

        //非静态方法(返回类型为string)也不起作用,返回了null
        Assert.assertTrue(locale.getCountry() == null);

        //自己new一个,也同样如此,方法都被mock了
        Locale chinaLocale = new Locale("zh","CN");
        Assert.assertTrue(chinaLocale.getCountry() == null);
    }

    @Test
    public  void testInjectable(@Injectable Locale locale){
        //静态方法不mock
        Assert.assertTrue(Locale.getDefault() != null);

        //非静态方法(返回类型为string)也不起作用了,返回null,但仅仅限于locale这个对象
        Assert.assertTrue(locale.getCountry() == null);

        //自己new一个,并不受影响
        Locale chinaLocale = new Locale("zh","CN");
        Assert.assertTrue(chinaLocale.getCountry().equals("CN"));
    }
}
  • @Injectable 也是告诉 JMockit生成一个Mocked对象,但@Injectable只是针对其修饰的实例,而@Mocked是针对其修饰类的所有实例。
  • 此外,@Injectable对类的静态方法,构造函数没有影响。因为它只影响某一个实例嘛!
  1. @Tested & @Injectable 两个好基友,通常搭配使用
    为便于演示,我们以电商网站下订单的场景为例:在买家下订单时,电商网站后台程序需要校验买家的身份(是否合法,例如是否在黑名单中),若下订单没有问题还要发邮件给买家。 相信下面的代码,你一定能看明白 。
// 邮件服务类,用于发邮件
public interface MailService {
 
    /**
     * 发送邮件
     * @param userId           邮件接受人id
     * @param content         邮件内容
     * @return 发送成功了,就返回true,否则返回false
     */
    public boolean sendMail(long userId, String content);
}
// 用户身份校验  
public interface UserCheckService {
    /**
     * 校验某个用户是否是合法用户
     * 
     * @param userId    用户ID
     * @return 合法的就返回true,否则返回false 
     */
    public boolean check(long userId);
}//订单服务类 ,用于下订单
import javax.annotation.Resource;

public class OrderService {
    //邮件服务类,用于向某用户发邮件
    MailService mailService;
    @Resource
    UserCheckService userCheckService;

    //构造函数
    public  OrderService(MailService mailService){
        this.mailService = mailService;
    }

    /*
    * 下订单
    * @param buyerId   买家ID
    * @param itemId    商品ID
    * @return 返回下订单是否成功
    * */
    public boolean submitOrder(long buyerId, long itemid){
        //先校验用户身份
        if(!userCheckService.check(buyerId)){
            //用户身份不合法
            return  false;
        }
        /*
        下单逻辑代码
        省略。。。。
        下单完成后,给买家发邮件
        * */
        if (!this.mailService.sendMail(buyerId, "下单成功")){
            //邮件发送失败
            return false;
        }
        return true;
    }
}

假设现在我们需要测试OrderService类的submitOrder方法,可是OrderService依赖MailService,UserCheckService类,在测试过程中,我们并不想真正连结邮件服务器,也不想连结校验用户身份的服务器校验用户身份,怎么办呢?
此时@Tested与@Injectable就排上用场了!请看下面的测试程序:

import mockit.Expectations;
import mockit.Injectable;
import mockit.Tested;
import org.junit.Test;

//@Tested 与@injectable搭配使用
public class TestedAndInjectable {
    //@Tested 修饰的类,表示是我们要测试对象,在这里表示,我想测试订单服务类。JMockit也会帮我们实例化这个测试对象
    @Tested
    OrderService orderService;
    long testUserId = 1234561;     //测试用户id
    long testItemId = 4567891;     //测试商品id

    //测试注入方式
    @Test
    public  void testSubmitOrder(@Injectable MailService mailService,
                                 @Injectable UserCheckService userCheckService){
        new Expectations(){
            {
               //当向testUserId发邮件时,假设都发成功了
               mailService.sendMail(testUserId,anyString);
               result = true;

               //当检验testUserId的身份时,假设该用户都是合法的
                userCheckService.check(testUserId);
                result = true;
            }
        };
        //JMockit 帮我们实例化了mailService了,并通过OrderService的构造函数,注入到OrderService对象中
        //JMockit 帮我们实例化了userCheckService了,并通过OrderService的属性,注入到OrderService对象中
        Assert.assertTrue(orderService.submitOrder(testUserId, testItemId));
    }
}
  1. @Tested & @Injectable功能总结

@Injectable 也表示一个Mocked对象,相比@Mocked,只不过只影响类的一个实例。而@Mocked默认是影响类的所有实例。@Tested表示被测试对象。如果该对象没有赋值,JMockit会去实例化它。

@Tested的构造函数有参数,则JMockit通过在测试属性&测试参数中查找@Injectable修饰的Mocked对象注入@Tested对象的构造函数来实例化,不然,则用无参构造函数来实例化。除了构造函数的注入,JMockit还会通过属性查找的方式,把@Injectable对象注入到@Tested对象中。

注入的匹配规则:先类型,再名称(构造函数参数名,类的属性名)。若找到多个可以注入的@Injectable,则选择最优先定义的@Injectable对象。当然,我们的测试程序要尽量避免这种情况出现。因为给哪个测试属性/测试参数加@Injectable,是人为控制的。

  1. 什么测试场景,我们要使用@Tested & @Injectable
    显然,当我们需要手工管理被测试类的依赖时,就需要用到@Tested & @Injectable。
    两者搭配起来用,JMockit就能帮我们轻松搞定被测试类及其依赖注入细节。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值