文章目录
- 🍃前言
- 🎄测试流程
- 🌴准备工作
- 🌲测试创建队列功能
- 🌳测试统计文件的读写
- 🎋测试将相应消息放入文件中
- 🎍测试读文件里的消息到内存
- 🍀测试删除消息
- 😎测试垃圾回收
- ⭕总结
🍃前言
本次开发任务,对前面我们所完成的 MessageFileManager 类里的方法进行测试
🎄测试流程
与前面 DataBaseManager 测试流程相似,我们都需要准备
- 执行每个用例之前的准备工作
- 执行每个用例之后的收尾工作
- 准备一些基础数据
然后进行一功能的测试
🌴准备工作
首先我们实例化一个 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(对硬盘中的消息操作)类》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下