一、前言
需求:需要一个测试框架,能来测试一个 IM
系统,同时适配当前业务逻辑。
测试那用 Jmeter
喽,Jmeter
也能测试 websocket
,干嘛要自己开发一个测试框架啊?
最重要的一点:
TCP
协议是自定义的,用Jmeter
等框架,无法很好集成。PS
:当然对Jmeter
不够深入。
那么面向一个 IM
系统,其对应的测试框架,需满足:
- 具有连贯性,上下文:在保持连接情况下,执行一定业务逻辑处理,例如:发消息、加群、加好友等
- 易接入:开发对接代码简单
- 生成多种不同报告
- 可扩展
那么,那就试试呗。
二、v1 版本
初期思考,这种自动化测试,需要满足:
- 自动执行:启动之后所有测试用例都能执行,一个测试用例失败不能影响其他测试用例
- 可以输出定制的报告:控制台打印、生成文件
- 足够简单:容易集成业务,可以开发,并且运行速度快
思考过程
思考过程:
- 测试用例应该是一个对象
- 测试用例应该相互隔离
- 如何运行多个测试用例?
- 如何保存测试用例运行时出现的异常?
(1)测试用例应该是一个对象
运行:是一种能力,那么可以抽象为接口 interface
:
public interface Test {
void run();
}
测试用例应该是一个对象,每个用例都是从一个模板出来的:
具有属性:用例名
name
public abstract class TestCase implements Test {
protected String name;
public TestCase() {
}
public TestCase(String name) {
this.name = name;
}
@Override
public void run() {
}
}
(2)测试用例应该相互隔离
测试用例应该是相互隔离的:
- 一个用例的运行不应该影响另外一个用例
- 运行测试用例之前需要一些准备工作
- 运行测试用例之后需要一些清理工作
引出设计模式中 - 模板方法模式,代码如下:
public abstract class TestCase implements Test {
protected String name;
public TestCase() {
}
public TestCase(String name) {
this.name = name;
}
@Override
public void run() {
setUp();
try{
runTest();
} finally {
tearDown();
}
}
protected void setUp() throws Exception {}
protected void runTest() throws Exception {}
protected void tearDown() throws Exception {}
}
(3)如何运行多个测试用例?
目前为止,此框架每次只能运行一个自定义的
TestCase
。
那能不能:
- 能不能 “透明” 运行多个?
- 调用方不用关心调用是一个还是多个?
这块就用到了设计模式中 组合模式,对应类图,如图:
代码如下:
public class TestSuite extends TestCase {
private final List<Test> fTests = new ArrayList<>();
@Override
public void run() {
for (Test test : this.fTests) {
test.run();
}
}
public void addTest(Test test) {
this.fTsets.add(test);
}
}
实际运行,例如:
TestSuite testSuite = new TestSuite();
testSuite.addTest(new CalculatorTest('test1'));
testSuite.addTest(new CalculatorTest('test2'));
TestSuite ts = new TestSuite();
ts.addTest(new CalculatorTest('test3'));
testSuite.addTest(ts);
testSuite.run();
(4)如何保存测试用例运行时出现的异常?
测试失败,代码抛出异常:
Error
。
这时候,引入:TestResult
这个类,来收集结果。
重要的 TestResult
如下:
public class TestResult {
private List<TestFailure> errors;
... ...
// 重要:
void run(final TestCase test) {
startTest(test);
try {
test.doRun();
} catch (Throwable e) {
addError(test, e);
}
endTest(test);
}
private void startTest(Test test) {
int count = test.countTestCases();
testCount += count;
}
private void endTest(Test test) {}
}
其他对应的修改,代码如下:
// Test.java 如下:
public interface Test {
void run(TestResult tr);
int countTestCases();
}
// TestCase.java 如下:
public abstract class TestCase implements Test {
... ...
// 重要:
@Override
public void run(TestResult testResult) {
testResult.run(this);
}
... ...
}
那么总结下,目前的调用过程吧:
小结
目前为止,用到了哪些设计模式:
每个思考步骤,对应一个设计模式。
- 命令模式:表达一个测试用例,即
Test
- 模板模式:完成数据的准备和清理,
setUp()
和tearDown()
- 组合模式:屏蔽一个和多个的差别,
List<Test>
- 收集参数模式:利用参数收集信息,隔离测试用例和测试结果
细心的同学已经发现,这不就是阉割版的 Junit
嘛!!!
是的。仿照了 Junit 3
,Junit 4
开始又改版了。
如下图,是 junit3
的框架:
但 Junit
有个重要思想:约定优于配置。
即,
Junit
会加载test
开头的方法作为测试用例。 现在看起来很简单,但想法很重要啊!!!
如果觉得文章对你有帮助,麻烦 点赞、评论、收藏 你的支持是我最大的动力!!!
最后小编在学习过程中整理了一些学习资料,可以分享给做java的工程师朋友们,相互交流学习,需要的可以加入我的学习交流群 716055499 即可免费获取Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)
作者:dingyu002
来源:dinyu002
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。