jdk8函数式接口在接口测试的应用

 

背景

无论是手工测试还是接口测试,我们都需要对测试结果进行校验。面对现在的测试人员越来越高的要求,我们不能再只是简单的去校验那些code、response_status字段,而是应该深入到对reponse每一个字段、数据库、缓存等业务底层信息的校验。因此,原先的校验方法已经不太适用。

原先的校验方法

以testng为例,原先一般接口测试代码的书写逻辑如下

public class CheckAccountEnableWithdrawTest extends TestBase {

    @Resource
    IMerchantWalletManageFacade merchantWalletManageFacade;

    @Test(dataProvider = "testData")
    public void testCheckAccountEnableWithdraw(String entityId, String withdrawAmt, AccountType accountType, boolean success){

        boolean result  = merchantWalletManageFacade.checkAccountEnableWithdraw(entityId,withdrawAmt,accountType); // 调用接口方法,相当于调用request方法,得到返回结果
        Assert.assertEquals(result,success); // 校验response值和期望的success值是否相同
    }

    @DataProvider
    public Object[][] testData(){
        return new Object[][] {
                {"99932014","1",AccountType.GUARANTEE,true}, // 是否可以提取担保账户,可以提取,期望返回true
                {"99932014","1",AccountType.PENDING_SETTLEMENT,false}, // 是否可以提取待结算账户,待结算账户不能直接体现,期望返回false
        };
    }

}

因为校验逻辑比较简单,只校验一个字段,直接这么写也没有什么问题。但是如果我要加入新的校验逻辑呢?

    @Test(dataProvider = "testData")
    public void testCheckAccountEnableWithdraw(String entityId, String withdrawAmt, AccountType accountType, boolean success){

        boolean result  = merchantWalletManageFacade.checkAccountEnableWithdraw(entityId,withdrawAmt,accountType);
        Assert.assertEquals(result,success);
        
        if(result  &&  success) {
            // 校验数据库和缓存
        }
        else {
            // 校验报错信息
        }
    }

上面的写法是一个可以参考的方法,但是这是我们设计测试用例的初衷吗?一条具体测试用例的设计,必然是单一路径的,不应该再加入任何的if else之类的逻辑,这违反了用例的单一职责原则。那么该如何设计我们的测试用例呢?

我们期望的是传递一个校验器给我们的测试用例,校验器里定义了我们的校验方法。怎么书写我们的校验器呢?我们需要传给测试用例一个“函数”,这个函数里定义了校验方法,这将用到jdk1.8里的函数式接口。

函数式接口

函数式接口是jdk1.8的新特性,结合stream等新功能,是java的一个里程碑式的新功能。所有的函数式接口,必然被FunctionalInterface注解所修饰。如Function接口所示。Function接口就是定义了一个“给定一个参数并且有返回值”的函数

@FunctionalInterface
public interface Function<T, R> {

    /**
     * 用给定的参数调用这个函数
     *
     * @param t 函数的参数
     * @return 函数的返回值
     */
    R apply(T t);    
}

再看个BiFunction的接口,定义一个“传递两个参数并返回值”的函数

@FunctionalInterface
public interface BiFunction<T, U, R> {

    /**
     * Applies this function to the given arguments.
     *
     * @param t 第一个参数
     * @param u 第二个参数
     * @return 返回值
     */
    R apply(T t, U u);

}

下面是一个BiFunction函数式接口的例子。具体逻辑看注释。

public class MyTest2 {
    public static void main(String[] args) {
        // 定义加法, jdk1.7写法。实现apply方法,integer1和integer2为该方法传递的参数,return值为方法的返回值
        BiFunction<Integer,Integer,Integer> addFunction = new BiFunction<Integer, Integer, Integer>() {
            @Override
            public Integer apply(Integer integer1, Integer integer2) {
                return integer1 + integer2;
            }
        };

        // 定义减法,BinaryOperator是BiFunction的子类,如果传参和返回值类型相同,可以用BinaryOperator代替BiFunction
        BinaryOperator<Integer> subFunction = new BinaryOperator<Integer>() {
            @Override
            public Integer apply(Integer integer, Integer integer2) {
                return integer - integer2;
            }
        };

        // 定义乘法,如果一个接口被@FunctionalInterface注解修饰,那么它可以被简化为lambda表达式。
        // 表达式左面是传递的参数,右边是被{}包围的函数体。如果函数体是单语句,那么单语句的执行结果就是返回值
        BinaryOperator<Integer> mulFunction = (integer, integer2) -> integer * integer2;


        BinaryOperator<Integer> divFunction = (integer, integer2) -> integer / integer2;

        Integer i1 = 4;
        Integer i2 = 2;

        System.out.println(run(i1,i2,addFunction)); // 加法,输出6
        System.out.println(run(i1,i2,subFunction)); // 减法,输出2
        System.out.println(run(i1,i2,mulFunction)); // 乘法,输出8
        System.out.println(run(i1,i2,divFunction)); // 除法,输出2


    }

    /**
     * 给定两个参数,传递一个函数,分别实现对这两个参数的加减乘除操作
     * @param int1 参数1
     * @param int2 参数2
     * @param opmethod BiFunction 定义一个(传递两个参数并且返回一个值)的函数
     * @return
     */
    public static Integer run(Integer int1, Integer int2, BiFunction<Integer,Integer,Integer> opmethod) {
        return opmethod.apply(int1,int2);
    }

}

怎么写测试用例

把校验器方法的具体实现写在@DataProvider中,在@Test方法中调用校验器方法,因为校验器只需传递一个Result值(接口的response)而不需要返回参数,可采用Consumer接口来实现,Consumer接口只需要实现一个void accept(T t)方法即可。这个方法即我们的测试用例校验方法

public class GetMyCommissionTest extends TestBase {

    @Resource
    ICommissionAccountFacade commissionAccountFacade;

    @Resource
    Config config;

    @Resource
    DruidDataSource accountDataSource;

    @Resource
    DruidDataSource marketAgentDataSource;

    @DataProvider // 具体的用例设计
    public Object[][] testData() {
        return new Object[][]{
                {config.getCustomerRegisterId(), new Consumer<Result<CommissionVO>>() {
                    @Override
                    public void accept(Result<CommissionVO> result) {
                        System.out.println(JSON.toJSONString(result));
                        Assert.assertTrue(result.isSuccess());
                        Assert.assertNotNull(result.getModel().getBalanceCommission());
                        Assert.assertNotNull(result.getModel().getPendingCommission());

                        DBHelper.setdruidDataSource(accountDataSource);
                        // 分库分表,要多次查询, 先查询到账号名称
                        List<DataMap> accountList = DBHelper.executeQuery(String.format("select * from inst_account_binding where brh_id='%s'",huaishiConfig.getCustomerRegisterId()));
                        Assert.assertEquals(accountList.size(),1);
                        Long accountNo = accountList.get(0).getLongValue("account_no");
                        // 再查询账户,查个人冻结账户和个人结算账户的余额,balanceCommission为这两者之和
                        List<DataMap> accountBaseInfoList = DBHelper.executeQuery(
                                String.format("select avail_bln from account_base_info where account_no=%s and account_type in ('010', '011') ", accountNo));
                        Assert.assertEquals(result.getModel().getBalanceCommission(),accountBaseInfoList.stream().map(dataMap -> dataMap.getLongValue("avail_bln")).reduce(0L,Long::sum));

                        // 查询待结算账户,从marketagentsoa里查询分销的待结算金额
                        DBHelper.setdruidDataSource(marketAgentDataSource);
                        // 先查询distributorId
                        List<DataMap> dataMaps = DBHelper.executeQuery("select id from d_distributor where user_id='"+ huaishiConfig.getCustomerRegisterId() +"' and is_valid=1");
                        Assert.assertEquals(dataMaps.size(),1);
                        String distributorId = dataMaps.get(0).getStringValue("id");
                        List<DataMap> pendingList =   DBHelper.executeQuery("select * from d_account where distributor_id = " + distributorId);
                        Assert.assertEquals(pendingList.size(), 1);
                        Assert.assertEquals(result.getModel().getPendingCommission().longValue(),pendingList.get(0).getLongValue("unsettled_balance"));

                    }
                }}, // 存在的账户,从account库获取已入账和待入账金额,从marketagent库获取分销待结算金额
                
                {"not exist account", new Consumer<Result<CommissionVO>>() {
                    @Override
                    public void accept(Result<CommissionVO> commissionVOResult) {
                        Assert.assertTrue(commissionVOResult.isSuccess());
                        Assert.assertEquals(commissionVOResult.getModel().getPendingCommission().longValue(),0L);
                        Assert.assertEquals(commissionVOResult.getModel().getBalanceCommission().longValue(),0L);
                    }
                }}, // 不存在的账户,入账金额和待结算金额都为0
        };
    }

    @Test(dataProvider = "testData")
    public void testGetMyCommission(String customerId, Consumer<Result<CommissionVO>> validator) {
        Result<CommissionVO> result = commissionAccountFacade.getMyCommission(customerId);
        validator.accept(result); // 只需调用校验器方法
    }

}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值