【消息队列开发】 测试MessageFileManager(对硬盘中的消息操作)类

简介: 【消息队列开发】 测试MessageFileManager(对硬盘中的消息操作)类

🍃前言

本次开发任务,对前面我们所完成的 MessageFileManager 类里的方法进行测试

🎄测试流程

与前面 DataBaseManager 测试流程相似,我们都需要准备

  1. 执行每个用例之前的准备工作
  2. 执行每个用例之后的收尾工作
  3. 准备一些基础数据

然后进行一功能的测试

🌴准备工作

首先我们实例化一个 MessageFileManager 的对象,方便后续进行调用

并提前给出两个队列的名字,这里只给了名字,并没有实例化,后续使用时,再具体实例化

在每个用例执行之前,我们都创建两个队列,队列名字为我们上面已经定义好了的

在每个用例执行之前,我们都需要销毁这两个队列

代码实现如下:

private MessageFileManager messageFileManager = new MessageFileManager();

private static final String queueName1 = "testQueue1";
private static final String queueName2 = "testQueue2";

// 这个方法是每个用例执行之前的准备工作
@BeforeEach
public void setUp() throws IOException {
    // 准备阶段, 创建出两个队列, 以备后用
    messageFileManager.createQueueFiles(queueName1);
    messageFileManager.createQueueFiles(queueName2);
}

// 这个方法就是每个用例执行完毕之后的收尾工作
@AfterEach
public void tearDown() throws IOException {
    // 收尾阶段, 就把刚才的队列给干掉.
    messageFileManager.destroyQueueFiles(queueName1);
    messageFileManager.destroyQueueFiles(queueName2);
}

🌲测试创建队列功能

在每个测试用例之前,我们都会进行创建队列

该项测试就是为了测试队列是否创建成功

我们依旧使用断言进行判断

我们只需要查看队列中的文件是否存在就行

@Test
public void testCreateFiles() {
    // 创建队列文件已经在上面 setUp 阶段执行过了. 此处主要是验证看看文件是否存在.
    File queueDataFile1 = new File(".data/" + queueName1 + "/queue_data.txt");
    Assertions.assertEquals(true, queueDataFile1.isFile());
    File queueStatFile1 = new File(".data/" + queueName1 + "/queue_stat.txt");
    Assertions.assertEquals(true, queueStatFile1.isFile());
    File queueDataFile2 = new File(".data/" + queueName1 + "/queue_data.txt");
    Assertions.assertEquals(true, queueDataFile2.isFile());
    File queueStatFile2 = new File(".data/" + queueName1 + "/queue_stat.txt");
    Assertions.assertEquals(true, queueStatFile2.isFile());
}

🌳测试统计文件的读写

首先我们需要构建一个 Stat 的对象,并给其相关属性进行赋值

然后接下来我i们开始调用相关方法,但是呢,关于测试文件的读写,在最初设计的时候我们进行了封装,只准内部使用。

所以这里我们使用反射的方式进行访问

恰好Spring 帮我们 封住好了一个工具类,我们这里直接使用就好

最后我们只需要读取相应的属性与我们写入的数据进行对比就好

@Test
public void testReadWriteStat() {
    MessageFileManager.Stat stat = new MessageFileManager.Stat();
    stat.totalCount = 100;
    stat.validCount = 50;
    // 此处就需要使用反射的方式, 来调用 writeStat 和 readStat 了.
    // Java 原生的反射 API 其实非常难用~~
    // 此处使用 Spring 帮我们封装好的 反射 的工具类.
    ReflectionTestUtils.invokeMethod(messageFileManager, "writeStat", queueName1, stat);

    // 写入完毕之后, 再调用一下读取, 验证读取的结果和写入的数据是一致的.
    MessageFileManager.Stat newStat = ReflectionTestUtils.invokeMethod(messageFileManager, "readStat", queueName1);
    Assertions.assertEquals(100, newStat.totalCount);
    Assertions.assertEquals(50, newStat.validCount);
    System.out.println("测试 readStat 和 writeStat 完成!");
}

🎋测试将相应消息放入文件中

既然要将消息放入队列中,那么首先我们得

构造出队列与消息

注意:此处构造的队列名一定要是我们前面给出的队列名里的一种,不然找不到相应的文件

然后我们将相应的队列与消息放送到文件里

这时候我们再读统计文件里的消息数目,与自己插入的数目是否一致

我们再读取整个数据,得到一个链表

我们再提取其中的对象,与我们放进去之前的对象进行对比,看是否相等

需要注意的是:比较数组时,我们不能使用 assertEquals了,而是使用assertArrayEquals

实现代码:

@Test
public void testSendMessage() throws IOException, MqException, ClassNotFoundException {
    // 构造出消息, 并且构造出队列.
    Message message = createTestMessage("testMessage");
    // 此处创建的 queue 对象的 name, 不能随便写, 只能用 queueName1 和 queueName2. 需要保证这个队列对象
    // 对应的目录和文件啥的都存在才行.
    MSGQueue queue = createTestQueue(queueName1);

    // 调用发送消息方法
    messageFileManager.sendMessage(queue, message);

    // 检查 stat 文件.
    MessageFileManager.Stat stat = ReflectionTestUtils.invokeMethod(messageFileManager, "readStat", queueName1);
    Assertions.assertEquals(1, stat.totalCount);
    Assertions.assertEquals(1, stat.validCount);

    // 检查 data 文件
    LinkedList<Message> messages = messageFileManager.loadAllMessageFromQueue(queueName1);
    Assertions.assertEquals(1, messages.size());
    Message curMessage = messages.get(0);
    Assertions.assertEquals(message.getMessageId(), curMessage.getMessageId());
    Assertions.assertEquals(message.getRoutingKey(), curMessage.getRoutingKey());
    Assertions.assertEquals(message.getDeliverMode(), curMessage.getDeliverMode());
    // 比较两个字节数组的内容是否相同, 不能直接使用 assertEquals 了.
    Assertions.assertArrayEquals(message.getBody(), curMessage.getBody());

    System.out.println("message: " + curMessage);
}

🎍测试读文件里的消息到内存

这里的测试方法其实与上面类似,构造队列与消息

然后一一去除进行对比,这里我们测试的数据更多

实现代码如下:

@Test
public void testLoadAllMessageFromQueue() throws IOException, MqException, ClassNotFoundException {
    // 往队列中插入 100 条消息, 然后验证看看这 100 条消息从文件中读取之后, 是否和最初是一致的.
    MSGQueue queue = createTestQueue(queueName1);
    List<Message> expectedMessages = new LinkedList<>();
    for (int i = 0; i < 100; i++) {
        Message message = createTestMessage("testMessage" + i);
        messageFileManager.sendMessage(queue, message);
        expectedMessages.add(message);
    }

    // 读取所有消息
    LinkedList<Message> actualMessages = messageFileManager.loadAllMessageFromQueue(queueName1);
    Assertions.assertEquals(expectedMessages.size(), actualMessages.size());
    for (int i = 0; i < expectedMessages.size(); i++) {
        Message expectedMessage = expectedMessages.get(i);
        Message actualMessage = actualMessages.get(i);
        System.out.println("[" + i + "] actualMessage=" + actualMessage);

        Assertions.assertEquals(expectedMessage.getMessageId(), actualMessage.getMessageId());
        Assertions.assertEquals(expectedMessage.getRoutingKey(), actualMessage.getRoutingKey());
        Assertions.assertEquals(expectedMessage.getDeliverMode(), actualMessage.getDeliverMode());
        Assertions.assertArrayEquals(expectedMessage.getBody(), actualMessage.getBody());
        Assertions.assertEquals(0x1, actualMessage.getIsValid());
    }
}

🍀测试删除消息

此时我们的测试思路依旧是构造一些消息写入文件,然后进行删除操作,最后读取剩余文件与写入文件进行对比

这一次我们插入10个消息数据,然后删除后面三个的消息数据

最后读取文件里面的内容,比对读取的消息长度与删除后的长度是否一样

然后再一一对比里面的数据是否一样

实现代码如下:

@Test
public void testDeleteMessage() throws IOException, MqException, ClassNotFoundException {
    // 创建队列, 写入 10 个消息. 删除其中的几个消息. 再把所有消息读取出来, 判定是否符合预期.
    MSGQueue queue = createTestQueue(queueName1);
    List<Message> expectedMessages = new LinkedList<>();
    for (int i = 0; i < 10; i++) {
        Message message = createTestMessage("testMessage" + i);
        messageFileManager.sendMessage(queue, message);
        expectedMessages.add(message);
    }

    // 删除其中的三个消息
    messageFileManager.deleteMessage(queue, expectedMessages.get(7));
    messageFileManager.deleteMessage(queue, expectedMessages.get(8));
    messageFileManager.deleteMessage(queue, expectedMessages.get(9));

    // 对比这里的内容是否正确.
    LinkedList<Message> actualMessages = messageFileManager.loadAllMessageFromQueue(queueName1);
    Assertions.assertEquals(7, actualMessages.size());
    for (int i = 0; i < actualMessages.size(); i++) {
        Message expectedMessage = expectedMessages.get(i);
        Message actualMessage = actualMessages.get(i);
        System.out.println("[" + i + "] actualMessage=" + actualMessage);

        Assertions.assertEquals(expectedMessage.getMessageId(), actualMessage.getMessageId());
        Assertions.assertEquals(expectedMessage.getRoutingKey(), actualMessage.getRoutingKey());
        Assertions.assertEquals(expectedMessage.getDeliverMode(), actualMessage.getDeliverMode());
        Assertions.assertArrayEquals(expectedMessage.getBody(), actualMessage.getBody());
        Assertions.assertEquals(0x1, actualMessage.getIsValid());
    }
}

😎测试垃圾回收

我们依旧需要进行构造数据

这次我们构造100条信息存入文件中

并记录此时的文件大小

然后我们删除0下标与偶数下标的消息

然后手动调用GC,读文件里面的内容

把之前消息偶数下标的删了, 剩下的就是奇数下标的元素了.

这时候新旧数据下标和的匹配关系就如下所示

  • 新:i = 0 旧 i = 1
  • 新:i = 1 旧 i = 3
  • 新:i = n 旧 i = 2*n + 1

以此我们来进行比对,并对比前后消息的长度

Assertions.assertTrue()方法来判断表达式的真假

执行代码如下:

@Test
public void testGC() throws IOException, MqException, ClassNotFoundException {
    // 先往队列中写 100 个消息. 获取到文件大小.
    // 再把 100 个消息中的一半, 都给删除掉(比如把下标为偶数的消息都删除)
    // 再手动调用 gc 方法, 检测得到的新的文件的大小是否比之前缩小了.
    MSGQueue queue = createTestQueue(queueName1);
    List<Message> expectedMessages = new LinkedList<>();
    for (int i = 0; i < 100; i++) {
        Message message = createTestMessage("testMessage" + i);
        messageFileManager.sendMessage(queue, message);
        expectedMessages.add(message);
    }

    // 获取 gc 前的文件大小
    File beforeGCFile = new File("./data/" + queueName1 + "/queue_data.txt");
    long beforeGCLength = beforeGCFile.length();

    // 删除偶数下标的消息
    for (int i = 0; i < 100; i += 2) {
        messageFileManager.deleteMessage(queue, expectedMessages.get(i));
    }

    // 手动调用 gc
    messageFileManager.gc(queue);

    // 重新读取文件, 验证新的文件的内容是不是和之前的内容匹配
    LinkedList<Message> actualMessages = messageFileManager.loadAllMessageFromQueue(queueName1);
    Assertions.assertEquals(50, actualMessages.size());
    for (int i = 0; i < actualMessages.size(); i++) {
        // 把之前消息偶数下标的删了, 剩下的就是奇数下标的元素了.
        // actual 中的 0 对应 expected 的 1
        // actual 中的 1 对应 expected 的 3
        // actual 中的 2 对应 expected 的 5
        // actual 中的 i 对应 expected 的 2 * i + 1
        Message expectedMessage = expectedMessages.get(2 * i + 1);
        Message actualMessage = actualMessages.get(i);

        Assertions.assertEquals(expectedMessage.getMessageId(), actualMessage.getMessageId());
        Assertions.assertEquals(expectedMessage.getRoutingKey(), actualMessage.getRoutingKey());
        Assertions.assertEquals(expectedMessage.getDeliverMode(), actualMessage.getDeliverMode());
        Assertions.assertArrayEquals(expectedMessage.getBody(), actualMessage.getBody());
        Assertions.assertEquals(0x1, actualMessage.getIsValid());
    }
    // 获取新的文件的大小
    File afterGCFile = new File("./data/" + queueName1 + "/queue_data.txt");
    long afterGCLength = afterGCFile.length();
    System.out.println("before: " + beforeGCLength);
    System.out.println("after: " + afterGCLength);
    Assertions.assertTrue(beforeGCLength > afterGCLength);
}

⭕总结

关于《【消息队列开发】 测试MessageFileManager(对硬盘中的消息操作)类》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下

相关文章
|
1月前
|
测试技术 网络安全
什么是软件测试? 软件测试都有什么岗位 ?软件测试和调试的区别? 软件测试和开发的区别? 一位优秀的测试人员应该具备哪些素质? 软件测试等相关概念入门篇
文章全面介绍了软件测试的基本概念、目的、岗位分类、与开发和调试的区别,并阐述了成为优秀测试人员应具备的素质和技能。
170 1
什么是软件测试? 软件测试都有什么岗位 ?软件测试和调试的区别? 软件测试和开发的区别? 一位优秀的测试人员应该具备哪些素质? 软件测试等相关概念入门篇
|
3天前
|
安全 测试技术 持续交付
云计算时代的软件开发与测试:高效、灵活、可扩展
云计算时代的软件开发与测试:高效、灵活、可扩展
|
28天前
|
人工智能 监控 测试技术
云应用开发平台测试
云应用开发平台测试
44 2
|
1月前
|
敏捷开发 测试技术
开发模型(瀑布、螺旋、scrum) 和 测试模型(V、W)、增量和迭代、敏捷(思想)及敏捷开发 scrum
文章详细介绍了软件开发过程中的不同开发模型(瀑布、螺旋、Scrum)和测试模型(V模型、W模型),以及增量和迭代的概念,最后阐述了敏捷思想及其在敏捷开发(如Scrum)中的应用。
58 0
开发模型(瀑布、螺旋、scrum) 和 测试模型(V、W)、增量和迭代、敏捷(思想)及敏捷开发 scrum
|
2月前
|
测试技术 持续交付 UED
软件测试的艺术与科学:平衡创新与质量的探索在软件开发的波澜壮阔中,软件测试如同灯塔,指引着产品质量的方向。本文旨在深入探讨软件测试的核心价值,通过分析其在现代软件工程中的应用,揭示其背后的艺术性与科学性,并探讨如何在追求技术创新的同时确保产品的高质量标准。
软件测试不仅仅是技术活动,它融合了创造力和方法论,是软件开发过程中不可或缺的一环。本文首先概述了软件测试的重要性及其在项目生命周期中的角色,随后详细讨论了测试用例设计的创新方法、自动化测试的策略与挑战,以及如何通过持续集成/持续部署(CI/CD)流程优化产品质量。最后,文章强调了团队间沟通在确保测试有效性中的关键作用,并通过案例分析展示了这些原则在实践中的应用。
71 1
|
2月前
|
测试技术 UED 开发者
软件测试的艺术:从代码审查到用户反馈的全景探索在软件开发的宇宙中,测试是那颗确保星系正常运转的暗物质。它或许不总是站在聚光灯下,但无疑是支撑整个系统稳定性与可靠性的基石。《软件测试的艺术:从代码审查到用户反馈的全景探索》一文,旨在揭开软件测试这一神秘面纱,通过深入浅出的方式,引领读者穿梭于测试的各个环节,从细微处着眼,至宏观视角俯瞰,全方位解析如何打造无懈可击的软件产品。
本文以“软件测试的艺术”为核心,创新性地将技术深度与通俗易懂的语言风格相结合,绘制了一幅从代码审查到用户反馈全过程的测试蓝图。不同于常规摘要的枯燥概述,这里更像是一段旅程的预告片,承诺带领读者经历一场从微观世界到宏观视野的探索之旅,揭示每一个测试环节背后的哲学与实践智慧,让即便是非专业人士也能领略到软件测试的魅力所在,并从中获取实用的启示。
|
3月前
|
测试技术 C# 开发者
“代码守护者:详解WPF开发中的单元测试策略与实践——从选择测试框架到编写模拟对象,全方位保障你的应用程序质量”
【8月更文挑战第31天】单元测试是确保软件质量的关键实践,尤其在复杂的WPF应用中更为重要。通过为每个小模块编写独立测试用例,可以验证代码的功能正确性并在早期发现错误。本文将介绍如何在WPF项目中引入单元测试,并通过具体示例演示其实施过程。首先选择合适的测试框架如NUnit或xUnit.net,并利用Moq模拟框架隔离外部依赖。接着,通过一个简单的WPF应用程序示例,展示如何模拟`IUserRepository`接口并验证`MainViewModel`加载用户数据的正确性。这有助于确保代码质量和未来的重构与扩展。
76 0
|
6天前
|
JSON Java 测试技术
SpringCloud2023实战之接口服务测试工具SpringBootTest
SpringBootTest同时集成了JUnit Jupiter、AssertJ、Hamcrest测试辅助库,使得更容易编写但愿测试代码。
34 3
|
1月前
|
JSON 算法 数据可视化
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
这篇文章是关于如何通过算法接口返回的目标检测结果来计算性能指标的笔记。它涵盖了任务描述、指标分析(包括TP、FP、FN、TN、精准率和召回率),接口处理,数据集处理,以及如何使用实用工具进行文件操作和数据可视化。文章还提供了一些Python代码示例,用于处理图像文件、转换数据格式以及计算目标检测的性能指标。
57 0
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
|
2月前
|
移动开发 JSON Java
Jmeter实现WebSocket协议的接口测试方法
WebSocket协议是HTML5的一种新协议,实现了浏览器与服务器之间的全双工通信。通过简单的握手动作,双方可直接传输数据。其优势包括极小的头部开销和服务器推送功能。使用JMeter进行WebSocket接口和性能测试时,需安装特定插件并配置相关参数,如服务器地址、端口号等,还可通过CSV文件实现参数化,以满足不同测试需求。
237 7
Jmeter实现WebSocket协议的接口测试方法

热门文章

最新文章