开源MMDQ测试用例

DDMQ作为典型的消息队列,现简单分析使用过程如下。
准备:
group: cg_whb_test
topic:whb_test_topic1
topic:whb_test_topic2
topic:whb_test_topic3

Producer

生产者使用比较简单,直接调用send方法即可。一般情况下,可以自行封装一层send。如:

    /**
     * 最简单的用法,只指定topic和字符串消息体(默认按UTF-8编码)。
     * @param body body
     * @param topic topic
     * @return boolean
     */
    public boolean send(String body, String topic) {
        try {
            CarreraProducer producer = this.buildCarreraProducer(topic);

            //指定iplist方式,服务发现方式不满足时,再用此方式
            //CarreraConfig config = getNoSDConfig();
            //CarreraProducer producer = new CarreraProducer(config);
            producer.start(); // 启动生产实例。这里会进行一些初始化操作。

            //0.最简单的用法,只指定topic和字符串消息体(默认按UTF-8编码)。
            Result result = producer.send(topic, body);
            //
            //--------------- 关闭生产实例 ---------------
            //
            producer.shutdown();
            if (null == result) {
                log.error("消息发送失败,body:[{}]", body);
                return false;
            }
            //强烈建议一定要在日志中打印生产的结果。
            // OK 和 CACHE_OK 两个结果都可以认为是生产成功了。
            if (result.getCode() == CarreraReturnCode.OK
                    || result.getCode() == CarreraReturnCode.CACHE_OK) {
                log.info("produce success");
                return true;
            }

            if (result.getCode() > CarreraReturnCode.CACHE_OK) {
                log.info("produce failure, body[{}], message:{}", body, result.getMsg()); // 失败的情况,根据code和msg做相应处理。
                return false;
            }
            return false;
        } catch (Exception e) {
            log.error("发送消息异常,body:{}, e:{}", body, e);
            return false;
        }
    }

Comsumer

1. 单元测试

测试代码分为3部分:

  • 配置方法:配置消费组等。
  • 消费方法:主要的消费逻辑,接收到message后的处理。
  • main主方法:用于启动消费方法。
public class CarreraConsumerExampleTest1 {
    private static final Logger LOGGER = LoggerFactory.getLogger(CarreraConsumerExampleTest1.class);

    private static final String groupName = "cg_whb_test";

    public static void simpleExample(long consumeTime) throws InterruptedException {
        //CarreraConfig config = getConfig("cg_your_groupName", "127.0.0.1:9713");
        CarreraConfig config = getSDConfig();

        final CarreraConsumer consumer = new CarreraConsumer(config);

        consumer.startConsume(new MessageProcessor() {
            @Override
            public Result process(Message message, Context context) {
                LOGGER.info("收到如下消息:{}",message.value); //收到如下消息:java.nio.HeapByteBuffer[pos=83 lim=109 cap=139]
                LOGGER.info("process key:{}, value.length:{}, offset:{}, context:{}", message.getKey(),
                        message.getValue().length, message.getOffset(), context);
                return Result.SUCCESS;
            }
        }, 5); // 每台server有2个线程,额外的一个随机分配。

        Thread.sleep(consumeTime); // consume for 10 seconds
        consumer.stop(); //1分钟便于测试,可以注释掉
    }

    public static void main(String[] args) throws TTransportException, InterruptedException {
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                LogManager.shutdown(); //shutdown log4j2.
            }
        }));

        LOGGER.info("start simpleExample...");
        simpleExample(60 * 1000);

    }

    // 不使用服务发现
    public static CarreraConfig getConfig(String groupName, String ipList) {
        CarreraConfig config = new CarreraConfig(groupName, ipList);
        config.setRetryInterval(500); // 拉取消息重试的间隔时间,单位ms。
        config.setMaxBatchSize(8);  //一次拉取的消息数量。
        return config;
    }

    // 使用服务发现
    private static CarreraConfig getSDConfig() {
        CarreraConfig config = new CarreraConfig(groupName, Env.valueOf("Test"));
        config.setRetryInterval(500); // 拉取消息重试的间隔时间,单位ms。
        config.setMaxBatchSize(8);  //一次拉取的消息数量。
        return config;
    }
}

启动main方法,并在控制台发送一条消息,看到结果:

INFO EndpointManagerSD:129 - update service completely
10:11:17,110  INFO CarreraConsumerExampleTest1:32 - 收到如下消息:java.nio.HeapByteBuffer[pos=82 lim=108 cap=138]
10:11:17,113  INFO CarreraConsumerExampleTest1:33 - process key:1nDFsGfZ0Q9jz0fo, value.length:26, offset:1, context:Context(groupId:cg_whb_test, topic:whb_test_topic1, qid:R_test_test-02_0)

2. springboot测试

在没有main方法启动消费方法的情况下,需要将消费方法发布为bean,并依靠容器来启动消费方法。

在前一节的例子中,主要是运行simpleExample方法。在spring bean注入的理念下,将该方法作为bean发布。

并且,我们注意到,消费配置中,我们仅仅配置了消费组,而没有配置topic,这意味着所有绑定该组的topic,将会被所有的startConsume随机消费。我们一般需要使用独立的方法消费指定的topic。官方例子有如下说明:

 /**
     * 如果某些topic中消息流量特别大,可以使用独立的线程消费该topic。
     *
     * @param consumeTime 消费的时间
     * @throws InterruptedException
     */
    public static void exampleWithExtraThreadsForSomeTopic(long consumeTime) throws InterruptedException {
        CarreraConfig config = getConfig("cg_your_groupName", "127.0.0.1:9713");
        final CarreraConsumer consumer = new CarreraConsumer(config);
        Map<String/*Topic*/, Integer/*该topic额外的线程数*/> extraThreads = new HashMap<String, Integer>();
        extraThreads.put("test-0", 2);
        //该配置下有6个消费线程,有4个消费test-0和test-1的消息, 另外2个线程只消费test-0.
        consumer.startConsume(new MessageProcessor() {
            @Override
            public Result process(Message message, Context context) {
                LOGGER.info("process key:{}, value.length:{}, offset:{}, context:{}", message.getKey(),
                        message.getValue().length, message.getOffset(), context);
                return Result.SUCCESS;
            }
        }, 4, extraThreads);
        Thread.sleep(consumeTime);
        consumer.stop();
    }

注意上述中 该注释对应的消费关系

//该配置下有6个消费线程,有4个消费test-0和test-1的消息, 另外2个线程只消费test-0

  • 当匿名内部类后第一个参数为0时,仅消费指定的topic;
  • 当匿名内部类后第一个参数不为0时,有其他topic时也会消费。

以下测试代码中,topic1topic2为指定方法消费;topic3由于没有指定,会随机选一个startConsume消费。

package cn.whbing.mqboot.test;

import com.xiaojukeji.carrera.consumer.thrift.Context;
import com.xiaojukeji.carrera.consumer.thrift.Message;
import com.xiaojukeji.carrera.consumer.thrift.client.CarreraConfig;
import com.xiaojukeji.carrera.consumer.thrift.client.CarreraConsumer;
import com.xiaojukeji.carrera.consumer.thrift.client.MessageProcessor;
import com.xiaojukeji.carrera.sd.Env;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;

import java.util.HashMap;
import java.util.Map;

@SpringBootConfiguration
public class CarreraConsumerExampleTest1 {
    private static final Logger LOGGER = LoggerFactory.getLogger(CarreraConsumerExampleTest1.class);

    private  static String groupName = "cg_whb_test";
    private  String topic1 = "whb_test_topic1";
    private  String topic2 = "whb_test_topic2";


    @Bean
    public CarreraConsumer getCarreraConsumer() {
        CarreraConfig config = getSDConfig();

        //指定iplist方式,服务发现方式不满足时,再用此方式
        //CarreraConfig config = getNoSDConfig("cg_capricornus_client", "10.95.121.43:9713;10.95.137.66:9713");
        CarreraConsumer carreraConsumer = new CarreraConsumer(config);

        //指定某topic,消费进程
        Map<String/*Topic*/, Integer/*该topic额外的线程数*/> extraThreads = new HashMap<>();
        extraThreads.put(topic1, 1);

        carreraConsumer.startConsume(new MessageProcessor() {
            @Override
            public Result process(Message message, Context context) {
                LOGGER.info("测试1收到如下消息:{}",message.value); //收到如下消息:java.nio.HeapByteBuffer[pos=83 lim=109 cap=139]
                LOGGER.info("process key:{}, value.length:{}, offset:{}, context:{}", message.getKey(),
                        message.getValue().length, message.getOffset(), context);
                return Result.SUCCESS;
            }
        }, 0,extraThreads); 

        return carreraConsumer;
    }

    @Bean
    public CarreraConsumer getCarreraConsumer2() {
        CarreraConfig config = getSDConfig();

        //指定iplist方式,服务发现方式不满足时,再用此方式
        //CarreraConfig config = getNoSDConfig("cg_capricornus_client", "10.95.121.43:9713;10.95.137.66:9713");
        CarreraConsumer carreraConsumer = new CarreraConsumer(config);

        //指定某topic,消费进程
        Map<String/*Topic*/, Integer/*该topic额外的线程数*/> extraThreads = new HashMap<>();
        extraThreads.put(topic2, 1);

        carreraConsumer.startConsume(new MessageProcessor() {
            @Override
            public Result process(Message message, Context context) {
                LOGGER.info("测试2收到如下消息:{}",message.value); //收到如下消息:java.nio.HeapByteBuffer[pos=83 lim=109 cap=139]
                LOGGER.info("process key:{}, value.length:{}, offset:{}, context:{}", message.getKey(),
                        message.getValue().length, message.getOffset(), context);
                return Result.SUCCESS;
            }
        }, 0,extraThreads); 

        return carreraConsumer;
    }
    // 使用服务发现
    private static CarreraConfig getSDConfig() {
        CarreraConfig config = new CarreraConfig(groupName, Env.valueOf("Test"));
        config.setRetryInterval(500); // 拉取消息重试的间隔时间,单位ms。
        config.setMaxBatchSize(8);  //一次拉取的消息数量。
        return config;
    }
}

其他说明:spring bean在初始化时,即@Bean的方法里,会被执行一次。

    @Bean
    public String test(){
        System.out.println("测试测试测试");
        return "返回结果";
    }

测试用例代码:https://github.com/whbing/DDMQ

<think>好的,我现在需要帮助用户寻找关于TPShop开源商城系统的测试用例示例。首先,我需要理解用户的具体需求。用户提到的是测试用例,特别是针对TPShop的商城系统。根据用户的引用内容,特别是引用[3],其中提到了接口测试用例的设计模板和测试点,这可能是一个重要的参考。 首先,我应该回顾用户提供的引用内容。引用[3]详细描述了接口测试的步骤,包括需求分析、API文档解析、测试用例设计、执行测试用例的工具(如Postman和Python+Requests)、缺陷跟踪、测试报告生成以及持续集成。此外,还提供了接口测试用例模板,包括用例编号、标题、请求方法、URL、参数、预期结果等。这些信息可以作为设计测试用例的基础。 接下来,我需要考虑TPShop系统的功能模块。常见的电商系统通常包括用户注册登录、商品管理、购物车、订单处理、支付集成、会员中心等模块。每个模块都需要设计相应的测试用例。例如,用户注册可能需要测试手机号验证码是否正确处理,商品搜索是否支持模糊查询,订单状态流转是否符合逻辑等。 然后,我需要结合引用[3]中的模板,为每个功能模块设计具体的测试用例。例如,用户登录模块可以设计正常登录、错误密码、无效账号等场景。每个用例需要包含请求方法、URL、参数、预期响应状态码和数据。同时,需要确保覆盖正向和逆向测试用例,以验证系统的健壮性。 另外,引用[2]提到了学之思在线考试系统的测试报告,其中涉及多种工具如JMeter、Postman、Selenium等。这可能提示用户对性能测试、接口测试和UI测试都有需求。因此,除了功能测试用例,可能还需要考虑性能测试用例,比如高并发下的用户登录响应时间,或者压力测试下的支付接口稳定性。 需要注意的是,用户提供的引用[1]提到TPshop的编程示例,可能涉及到系统的基本操作和扩展功能。因此,测试用例可能需要涵盖自定义功能模块,比如促销活动的创建与管理,确保这些扩展功能与核心系统兼容。 在整理测试用例时,还要考虑数据准备,比如测试账号、测试商品信息等,确保测试的可重复性和准确性。此外,引用[3]中提到的持续集成部分,可能需要在测试用例设计中加入自动化测试的考虑,比如使用Jenkins进行持续集成,自动化执行测试用例并生成报告。 最后,需要检查测试用例是否符合常见的测试标准,如边界值分析、等价类划分、错误推测法等。例如,商品价格字段可能需要测试负数、零、极大值等边界情况,确保系统能正确处理异常输入。 总结来说,我需要根据用户提供的引用内容,尤其是引用[3]中的模板,结合电商系统的常见功能模块,设计出结构清晰、覆盖全面的测试用例,同时考虑功能、接口、性能等多方面的测试需求,并确保用例的可执行性和自动化兼容性。</think>以下是为TPShop开源商城系统整理的测试用例示例,结合电商系统核心功能及接口测试规范设计[^3]: --- ### 一、用户模块测试用例 **1. 用户注册接口** $$请求格式:POST /api/user/register$$ | 用例编号 | 测试标题 | 请求参数 | 预期结果 | |---------|---------|---------|---------| | TC001 | 正常注册 | {phone: "13800138000", code: "1234", password: "Tp123456"} | 状态码200,返回用户ID | | TC002 | 重复手机号 | {phone: "13800138000", code: "1234", password: "Tp123456"} | 状态码400,错误提示"手机号已注册" | **2. 用户登录接口** $$请求格式:POST /api/user/login$$ | TC003 | 正确密码登录 | {username: "admin", password: "Tp@123456"} | 状态码200,返回token | | TC004 | 错误密码登录 | {username: "admin", password: "WrongPwd"} | 状态码401,提示"密码错误" | --- ### 二、商品模块测试用例 **1. 商品搜索接口** $$请求格式:GET /api/goods/search?keyword=手机$$ | TC005 | 模糊搜索 | keyword=手机 | 返回包含"手机"的商品列表 | | TC006 | 空关键词 | keyword= | 返回全部商品(需验证分页逻辑) | **2. 商品详情接口** $$请求格式:GET /api/goods/{id}$$ | TC007 | 存在商品ID | id=1001 | 返回完整商品信息,包含库存数量 | | TC008 | 无效商品ID | id=99999 | 状态码404,提示"商品不存在" | --- ### 三、订单模块测试用例 **1. 创建订单接口** $$请求格式:POST /api/order/create$$ ```json 请求体示例: { "goods_list": [ {"goods_id": 1001, "quantity": 2}, {"goods_id": 1002, "quantity": 1} ], "address_id": 5 } ``` | TC009 | 正常下单 | 有效商品和地址 | 生成待支付订单 | | TC010 | 库存不足 | 商品数量超过库存 | 状态码400,提示"库存不足" | **2. 订单支付回调测试** $$模拟支付平台请求:POST /api/payment/notify$$ | TC011 | 支付成功通知 | 包含有效签名和订单号 | 订单状态变更为"已支付" | --- ### 四、性能测试用例(使用JMeter)[^2] 1. **并发用户测试** - 场景:500用户同时进行商品搜索 - 预期:平均响应时间<2秒,错误率<0.1% 2. **压力测试** - 场景:持续10分钟生成订单请求 - 验证点:数据库连接池无溢出,消息队列堆积<100 --- ### 五、安全测试要点 1. SQL注入测试:在搜索框输入`' OR 1=1 --` 2. XSS攻击测试:在商品评价提交`<script>alert(1)</script>` 3. 越权访问:普通用户尝试访问`/api/admin/userlist` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值