qileilove

blog已经转移至github,大家请访问 http://qaseven.github.io/

CPPUTest 单元测试框架

CPPUTest 虽然名称上看起来是 C++ 的单元测试框架, 其实它也是支持测试 C 代码的.
  本文主要介绍用CPPUTest来测试 C 代码. (C++没用过, 平时主要用的是C) C++相关的内容都省略了.
  本文基于 debian v7.6 x86_64.
  1. CPPUTest 安装
  现在各个Linux的发行版的源都有丰富的软件资源, 而且安装方便.
  但是如果想要在第一时间使用最新版本的开源软件, 还是得从源码安装.
  debian系统为了追求稳定性, apt源中的软件一般都比较旧. 所以本文中的例子是基于最新源码的CPPUTest.
  1.1 apt-get 安装
  $ sudo apt-get install cpputest
  1.2 源码安装
  1. 下载源码, 官网: http://cpputest.github.io/
  2. 编译源码
  $ tar zxvf cpputest-3.6.tar.gz
  $ cd cpputest-3.6/
  $ ./configure
  $ make
  最后我没有实际安装, 而是直接使用编译出的二进制。
  2. CPPUTest 介绍
  2.1 构造待测试代码 (C语言)
/* file: sample.h */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Student
{
char* name;
int score;
};
void ret_void(void);
int ret_int(int, int);
double ret_double(double, double);
char* ret_pchar(char*, char*);
struct Student* init_student(struct Student* s, char* name, int score);
/* file: sample.c */
#include "sample.h"
#ifndef CPPUTEST
int main(int argc, char *argv[])
{
char* pa;
char* pb;
pa = (char*) malloc(sizeof(char) * 80);
pb = (char*) malloc(sizeof(char) * 20);
strcpy(pa, "abcdefg\0");
strcpy(pb, "hijklmn\0");
printf ("Sample Start......\n");
ret_void();
printf ("ret_int: %d\n", ret_int(100, 10));
printf ("ret_double: %.2f\n", ret_double(100.0, 10.0));
printf ("ret_pchar: %s\n", ret_pchar(pa, pb));
struct Student* s = (struct Student*) malloc(sizeof(struct Student));
s->name = (char*) malloc(sizeof(char) * 80);
init_student(s, "test cpputest", 100);
printf ("init_Student: name=%s, score=%d\n", s->name, s->score);
printf ("Sample End  ......\n");
free(pa);
free(pb);
free(s->name);
free(s);
return 0;
}
#endif
void ret_void()
{
printf ("Hello CPPUTest!\n");
}
/* ia + ib */
int ret_int(int ia, int ib)
{
return ia + ib;
}
/* da / db */
double ret_double(double da, double db)
{
return da / db;
}
/* pa = pa + pb */
char* ret_pchar(char* pa, char* pb)
{
return strcat(pa, pb);
}
/* s->name = name, s->score = score */
void init_student(struct Student* s, char* name, int score)
{
strcpy(s->name, name);
s->score = score;
}
2.2 测试用例的组成, 写法
  CPPUTest 的测试用例非常简单, 首先定义一个 TEST_GROUP, 然后定义属于这个 TEST_GROUP 的 TEST.
  需要注意的地方是:
  1. 引用 CPPUTest 中的2个头文件
  #include <CppUTest/CommandLineTestRunner.h>
  #include <CppUTest/TestHarness.h>
  2. 引用 C 头文件时, 需要使用 extern "C" {}
  extern "C"
  {
  #include "sample.h"
  }
  下面的例子是测试 sample.c 中 ret_int 的代码.
  构造了一个测试成功, 一个测试失败的例子
/* file: test.c */
#include <CppUTest/CommandLineTestRunner.h>
#include <CppUTest/TestHarness.h>
extern "C"
{
#include "sample.h"
}
/* 定义个 TEST_GROUP, 名称为 sample */
TEST_GROUP(sample)
{};
/* 定义一个属于 TEST_GROUP 的 TEST, 名称为 ret_int_success */
TEST(sample, ret_int_success)
{
int sum = ret_int(1, 2);
CHECK_EQUAL(sum, 3);
}
/* 定义一个属于 TEST_GROUP 的 TEST, 名称为 ret_int_failed */
TEST(sample, ret_int_failed)
{
int sum = ret_int(1, 2);
CHECK_EQUAL(sum, 4);
}
int main(int argc, char *argv[])
{
CommandLineTestRunner::RunAllTests(argc, argv);
return 0;
}
  2.3 测试用例结果判断 ( fail, 各种assert等等)
  测试完成后, 可以用 CPPUTest 提供的宏来判断测试结果是否和预期一致.
  CPPUTest 提供的用于判断的宏如下: (上面的测试代码就使用了 CHECK_EQUAL)
  2.4 运行测试用例时的编译选项配置 (主要是C语言相关的)
  这一步是最关键的, 也就是编译出单元测试文件. 下面是 makefile 的写法, 关键位置加了注释.
# makefile for sample cpputest
CPPUTEST_HOME = /home/wangyubin/Downloads/cpputest-3.6
CC      := gcc
CFLAGS    := -g -Wall
CFLAGS  += -std=c99
CFLAGS  += -D CPPUTEST            # 编译测试文件时, 忽略sample.c的main函数, sample.c的代码中用了宏CPPUTEST
# CPPUTest 是C++写的, 所以用 g++ 来编译 测试文件
CPP     := g++
CPPFLAGS  := -g -Wall
CPPFLAGS  += -I$(CPPUTEST_HOME)/include
LDFLAGS := -L$(CPPUTEST_HOME)/lib -lCppUTest
sample: sample.o
sample.o: sample.h sample.c
$(CC) -c -o sample.o sample.c $(CFLAGS)
# 追加的测试程序编译
test: test.o sample.o
$(CPP) -o $@ test.o sample.o $(LDFLAGS)
test.o: sample.h test.c
$(CPP) -c -o test.o test.c $(CPPFLAGS)
.PHONY: clean
clean:
@echo "clean..."
rm -f test sample
rm -f sample.o test.o
  编译测试文件
  make test  <-- 会生成一个文件名为 test 可执行文件
  编译sample程序时, 需要把 "CFLAGS  += -D CPPUTEST" 这句注释掉, 否则没有main函数.
运行可执行文件 test 就可以实施测试.
$ ./test    <-- 默认执行, 没有参数
test.c:34: error: Failure in TEST(sample, ret_int_failed)
expected <3>
but was  <4>
difference starts at position 0 at: <          4         >
^
..
Errors (1 failures, 2 tests, 2 ran, 2 checks, 0 ignored, 0 filtered out, 1 ms)
=================================================================================
$ ./test -c   <-- -c 执行结果加上颜色 (成功绿色, 失败红色)
test.c:34: error: Failure in TEST(sample, ret_int_failed)
expected <3>
but was  <4>
difference starts at position 0 at: <          4         >
^
..
Errors (1 failures, 2 tests, 2 ran, 2 checks, 0 ignored, 0 filtered out, 1 ms) <-- bash中显示红色
=================================================================================
$ ./test -v  <-- -v 显示更为详细的信息
TEST(sample, ret_int_failed)
test.c:34: error: Failure in TEST(sample, ret_int_failed)
expected <3>
but was  <4>
difference starts at position 0 at: <          4         >
^
- 1 ms
TEST(sample, ret_int_success) - 0 ms
Errors (1 failures, 2 tests, 2 ran, 2 checks, 0 ignored, 0 filtered out, 1 ms)
=================================================================================
$ ./test -r 2   <-- -r 指定测试执行的次数, 这里把测试重复执行2遍
Test run 1 of 2
test.c:34: error: Failure in TEST(sample, ret_int_failed)
expected <3>
but was  <4>
difference starts at position 0 at: <          4         >
^
..
Errors (1 failures, 2 tests, 2 ran, 2 checks, 0 ignored, 0 filtered out, 0 ms)
Test run 2 of 2
test.c:34: error: Failure in TEST(sample, ret_int_failed)
expected <3>
but was  <4>
difference starts at position 0 at: <          4         >
^
..
Errors (1 failures, 2 tests, 2 ran, 2 checks, 0 ignored, 0 filtered out, 1 ms)
=================================================================================
$ ./test -g sample    <-- -g 指定 TEST_GROUP, 本例其实只有一个 TEST_GROUP sample
test.c:34: error: Failure in TEST(sample, ret_int_failed)
expected <3>
but was  <4>
difference starts at position 0 at: <          4         >
^
..
Errors (1 failures, 2 tests, 2 ran, 2 checks, 0 ignored, 0 filtered out, 1 ms)
=================================================================================
$ ./test -n ret_int_success    <-- -s 指定执行其中一个 TEST, 名称为 ret_int_success
.
OK (2 tests, 1 ran, 1 checks, 0 ignored, 1 filtered out, 0 ms)
=================================================================================
$ ./test -v -n ret_int_success  <-- 参数也可以搭配使用
TEST(sample, ret_int_success) - 0 ms
OK (2 tests, 1 ran, 1 checks, 0 ignored, 1 filtered out, 0 ms)
  2.6 补充: setup and teardown
  上面 test.c 文件中 TEST_GROUP(sample) 中的代码是空的, 其实 CPPUTest 中内置了 2 个调用 setup 和 teardown.
  在 TEST_GROUP 中实现这2个函数之后, 每个属于这个 TEST_GROUP 的 TEST 在执行之前都会调用 setup, 执行之后会调用 teardown.
  修改 test.c 中的 TEST_GROUP 如下:
/* 定义个 TEST_GROUP, 名称为 sample */
TEST_GROUP(sample)
{
void setup()
{
printf ("测试开始......\n");
}
void teardown()
{
printf ("测试结束......\n");
}
};
  重新执行测试: (每个测试之前, 之后都多了上面的打印信息)
$ make clean
clean...
rm -f test sample
rm -f sample.o test.o
$ make test
g++ -c -o test.o test.c -g -Wall -I/home/wangyubin/Downloads/cpputest-3.6/include
gcc -c -o sample.o sample.c -g -Wall -std=c99 -D CPPUTEST
g++ -o test test.o sample.o -L/home/wangyubin/Downloads/cpputest-3.6/lib -lCppUTest
$ ./test -v
TEST(sample, ret_int_failed)测试开始......
test.c:44: error: Failure in TEST(sample, ret_int_failed)
expected <3>
but was  <4>
difference starts at position 0 at: <          4         >
^
  测试结束......
  - 0 ms
  TEST(sample, ret_int_success)测试开始......
  测试结束......
  - 0 ms
  Errors (1 failures, 2 tests, 2 ran, 2 checks, 0 ignored, 0 filtered out, 0 ms)
2.7 内存泄漏检测插件
  内存泄漏一直是C/C++代码中令人头疼的问题, 还好, CPPUTest 中提供了检测内存泄漏的插件, 使用这个插件, 可使我们的代码更加健壮.
  使用内存检测插件时, 测试代码 和 待测代码 在编译时都要引用.
  -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorMallocMacros.h
  makefile 修改如下:
# makefile for sample cpputest
CPPUTEST_HOME = /home/wangyubin/Downloads/cpputest-3.6
CC      := gcc
CFLAGS    := -g -Wall
CFLAGS  += -std=c99
CFLAGS  += -D CPPUTEST            # 编译测试文件时, 忽略sample.c的main函数, sample.c的代码中用了宏CPPUTEST
# CPPUTest 是C++写的, 所以用 g++ 来编译 测试文件
CPP     := g++
CPPFLAGS  := -g -Wall
CPPFLAGS  += -I$(CPPUTEST_HOME)/include
LDFLAGS := -L$(CPPUTEST_HOME)/lib -lCppUTest
# 内存泄露检测
MEMFLAGS = -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorMallocMacros.h
sample: sample.o
sample.o: sample.h sample.c
$(CC) -c -o sample.o sample.c $(CFLAGS) $(MEMFLAGS)
# 追加的测试程序编译
test: test.o sample.o
$(CPP) -o $@ test.o sample.o $(LDFLAGS)
test.o: sample.h test.c
$(CPP) -c -o test.o test.c $(CPPFLAGS)  $(MEMFLAGS)
.PHONY: clean
clean:
@echo "clean..."
rm -f test sample
rm -f sample.o test.o
  修改 sample.c 中的 init_student 函数, 构造一个内存泄漏的例子.
/* s->name = name, s->score = score */
void init_student(struct Student* s, char* name, int score)
{
char* name2 = NULL;
name2 = (char*) malloc(sizeof(char) * 80); /* 这里申请的内存, 最后没有释放 */
strcpy(s->name, name2);
strcpy(s->name, name);
s->score = score;
}
  修改 test.c 追加一个测试 init_student 函数的测试用例
  TEST(sample, init_student)
  {
  struct Student *stu = NULL;
  stu = (struct Student*) malloc(sizeof(struct Student));
  char name[80] = {'t', 'e', 's', 't', '\0'};
  init_student(stu, name, 100);
  free(stu);
  }
  执行测试, 可以发现测试结果中提示 sample.c 72 行有内存泄漏风险,
  这一行正是 init_student 函数中用 malloc 申请内存的那一行.
$ make clean
clean...
rm -f test sample
rm -f sample.o test.o
$ make test
g++ -c -o test.o test.c -g -Wall -I/home/wangyubin/Downloads/cpputest-3.6/include  -include /home/wangyubin/Downloads/cpputest-3.6/include/CppUTest/MemoryLeakDetectorMallocMacros.h
gcc -c -o sample.o sample.c -g -Wall -std=c99 -D CPPUTEST             -include /home/wangyubin/Downloads/cpputest-3.6/include/CppUTest/MemoryLeakDetectorMallocMacros.h
g++ -o test test.o sample.o -L/home/wangyubin/Downloads/cpputest-3.6/lib -lCppUTest
$ ./test -v -n init_student
  TEST(sample, init_student)测试开始......
  测试结束......
  test.c:47: error: Failure in TEST(sample, init_student)
Memory leak(s) found.
Alloc num (4) Leak size: 80 Allocated at: sample.c and line: 72. Type: "malloc"
Memory: <0x120c5f0> Content: ""
Total number of leaks:  1
NOTE:
Memory leak reports about malloc and free can be caused by allocating using the cpputest version of malloc,
but deallocate using the standard free.
If this is the case, check whether your malloc/free replacements are working (#define malloc cpputest_malloc etc).
- 0 ms
Errors (1 failures, 3 tests, 1 ran, 0 checks, 0 ignored, 2 filtered out, 0 ms)

posted @ 2014-10-30 10:36 顺其自然EVO 阅读(631) | 评论 (0)编辑 收藏

如何在VS2013中进行Boost单元测试

 对于如何在VS2013中进行Boost单元测试,这方面资料太少。自己也因此走了不少弯路。下文将会阐述一下如何在VS2013中进行Boost单元测试。
  在开始Boost单元测试之前,我们需要先安装VS2013插件Boost Unit Test Adapter (Update 3) 以及编译Boost库。Boost Unit Test Adapte可以在VS2013中的“工具->扩展与更新”中找到并安装。对于Boost Unit Test Adapter所支持的Boost库版本请参考网页。我选择的是版本号为1.55.0的Boost库(可以在其官网下载得到)。在编译Boost库的时候,可以参考教程及博文。我选择的是完全编译(bjam --toolset=msvc-12.0 --build-type=complete)。
  下文以几个步骤来阐述:
  1. 新建解决方案及工程
  接下来,我们新建一个BoostUnitTest解决方案,然后在该方案下添加(鼠标右击解决方案新建项目)两个项目。第一个项目是空的“WIN32”项目“Tested”,另一个是“Boost Unit Test Project”项目(新建项目->模板->Visual C++->Test下)“BoostUnitTest”。如下图:
  2. 在被测试工程中添加文件
  在Tested工程中添加一个头文件tested.h及源文件tested.cpp. 具体代码如下
1 #include <iostream>
2
3 using namespace std;
4
5 class Tested
6 {
7 public:
8
9     Tested();
10     virtual ~Tested();
11     int add(const int a, const int b);
12
13 private:
14
15 };
1 #include "tested.h"
2
3 Tested::Tested()
4 {
5
6 }
7
8 Tested::~Tested()
9 {
10
11 }
12
13 int Tested::add(const int a, const int b)
14 {
15     return a + b;
16 }
  在这里,我们并不需要新建一个main函数对这个类tested进行测试(因为我们已经有单元测试了),但一个程序默认是需要main函数的,所以在需要在Tested项目属性中进行这样的设置(“配置类型”改为“动态库(.dll)”见下图):
接着,“生成”该工程,产生tested.obj文件。
  3. 配置Boost单元测试工程
  新建的Boost单元测试工程中有两个源文件“BoostUnitTestSample.cpp”及“BoostUnitTest.cpp”(还有stdafx.h、stdafx.cpp、targetver.h),前一个文件是样例,可以不要,后一个文件可以当作我们的单元测试源文件。
  先对该工程进行配置:
  4. 进行Boost单元测试
  注:我们在这时只进行简单的单元测试,更加复杂的测试请参考文章最后给出的链接。
  在BoostUnitTest工程中的文件“BoostUnitTest.cpp”(也可新建)添加如下代码:
  点击“生成->生成解决方案”(预先打开“测试->窗口->测试资源管理器”)可以看到在“测试资源管理器”中出现了“BoostUnitTest”这个单元测试用例,如下图:
  注:如果电脑安装有杀毒软件(如360),“生成解决方案”的时候可能会提示:error LNK1104: 无法打开文件“...\BoostUnitTest\Debug\Tested.dll"。这是因为杀毒软件拦截了单元测试工程对被测试工程.dll文件的访问。比较简单的方法是将杀毒软件关闭就OK了。
  点击“全部运行”,可以看到该测试用例变绿,说明测试通过,如下图: 如果我们将“BoostUnitTest.cpp”中的第13行改成:
  BOOST_CHECK(tmpTested->add(2, 2) == 3);
  单元测试运行结果是不通过,如下图:
  至此,如何进行一个简单的Boost单元测试的过程就完成了。
  // 添加于2014.10.18 ---------------------------------------------------------------------------
  现在,我在之前程序的基础上又添加了一点异常测试,相关的源代码如下:
1 #include <iostream>
2
3 using namespace std;
4
5 class Tested
6 {
7 public:
8
9     Tested();
10     virtual ~Tested();
11     int add(const int a, const int b);
12     void testException();
13
14 private:
15
16 };
1 #include "tested.h"
2
3 Tested::Tested()
4 {
5
6 }
7
8 Tested::~Tested()
9 {
10
11 }
12
13 int Tested::add(const int a, const int b)
14 {
15     return a + b;
16 }
17
18 void Tested::testException()
19 {
20     throw logic_error("my throw");    // 抛出一个逻辑错误异常
21 }
1 #define BOOST_TEST_MODULE Tested_Module                                // 主测试套件,一个测试项目中只能有一个主测试套件
2
3 #include "stdafx.h"
4 #include "D:\VSProject\BoostUnitTest\BoostUnitTest\Tested\tested.h"    // 待测工程头文件
5
6 struct Tested_Fixture                                                // 测试夹具
7 {
8     Tested_Fixture()
9     {
10         BOOST_TEST_MESSAGE("setup fixture");
11         tmpTested = new Tested();
12     }
13     ~Tested_Fixture()
14     {
15         BOOST_TEST_MESSAGE("teardown fixture");
16         delete tmpTested;
17     }
18     Tested * tmpTested;
19 };
20
21 BOOST_FIXTURE_TEST_SUITE(Tested_test, Tested_Fixture)                // 测试套件
22
23 BOOST_AUTO_TEST_CASE(Tested_Method_add_Test)                        // 测试用例
24 {
25      // TODO: Your test code here
26     BOOST_WARN(tmpTested->add(2, 2) == 4);                            // WARN型预言检测
27     BOOST_CHECK(tmpTested->add(2, 2) == 4);                            // CHECK型预言检测
28     BOOST_REQUIRE(tmpTested->add(2, 2) == 4);                        // REQUIRE型预言检测
29
30 }
31
32 BOOST_AUTO_TEST_CASE(Tested_Method_testException_Test)                // 测试用例
33 {
34     // TODO: Your test code here
35     BOOST_REQUIRE_NO_THROW(tmpTested->testException());                // 验证是否无异常抛出,是则为真
36     BOOST_REQUIRE_THROW(tmpTested->testException(), logic_error);    // 验证抛出的是否是logic_error异常
37     BOOST_REQUIRE_THROW(tmpTested->testException(), runtime_error);    // 验证抛出的是否是runtime_error异常
38
39 }
40
41 BOOST_AUTO_TEST_SUITE_END()
  很显示,程序的运行结果如下:
  35 BOOST_REQUIRE_NO_THROW(tmpTested->testException());              // 测试不通过
  36 BOOST_REQUIRE_THROW(tmpTested->testException(), logic_error);    // 测试通过
  37 BOOST_REQUIRE_THROW(tmpTested->testException(), runtime_error);  // 测试不通过
  如果要进行更复杂的测试,可以参考官方文档。

posted @ 2014-10-30 10:31 顺其自然EVO 阅读(222) | 评论 (0)编辑 收藏

VM性能的快速测试方法

 前段时间陆续发布了一些对公有云服务性能评测的数据。经常有同行问我怎么样去做这些性能评测。其实这些性能评测都很简单,任何一个具备Linux基础知识的工程师都可以完成。我们通常使用UnixBench来评估虚拟机CPU性能,mbw来评估内存性能,iozone来评估文件IO性能,iperf来评估网络性能,pgbench来评估数据库性能。在这里我将我自己做性能测试的过程整理一下,供各位同行参考。
  (0)安装必要的软件
  假定VM的操作系统是Ubuntu,可以按照如下步骤安装必要的软件:
sudo apt-get install python-software-properties
sudo add-apt-repository ppa:pitti/postgresql
sudo apt-get update
apt-get install libx11-dev libgl1-mesa-dev libxext-dev perl perl-modules make gcc nfs-common postgresql-9.1 postgresql-contrib-9.1 mbw iperf
cd ~
wget http://www.iozone.org/src/current/iozone3_414.tar
wget http://byte-unixbench.googlecode.com/files/UnixBench5.1.3.tgz
tar xvf iozone3_414.tar
tar zxvf UnixBench5.1.3.tgz
cd ~/iozone3_414/src/current
make
cd ~/UnixBench
make
  (1)CPU性能测试
  我们使用UnixBench来进行CPU性能测试。UnixBench是一套具有悠久历史的性能测试工具,其测试结果反映的是一台主机的综合性能。从理论上来说UnixBench测试结果与被测试主机的CPU、内存、存储、操作系统都有直接的关系。但是根据我们的观察,对于现代的计算机系统来说,UnixBench测试结果受CPU 处理能力的影响更大一些。因此,在这里我们用UnixBench测试结果来代表虚拟机的vCPU 处理能力。每个UnixBench测试结果包括两个数据,一个是单线程测试结果,另一个是多线程测试结果(虚拟机上有几颗虚拟CPU,就有几个并发的测试线程)。
  cd ~/UnixBench
  ./Run
  下面是一个可供参考的测试结果。在这个测试中使用了两台物理机,每台物理机各配置一颗Intel Core i3 540 @ 3.07 GHz (双核四线程),16 GB内存(DDR3 @ 1333 MHz),一块Seagate ST2000DL003-9VT1硬盘(SATA,2TB,5900RPM),运行Ubuntu 10.04 AMD64 Server操作系统,使用的文件系统为ext4,使用的Hypervisor为KVM(qemu-kvm-0.12.3)。我们分别测试了宿主机、磁盘映像以文件格式(RAW格式,没有启用virtio)存储在本地磁盘上的虚拟机、磁盘映像以文件格式(RAW格式,没有启用virtio)存储在NFS上的虚拟机的CPU性能。虚拟机的配置为2 颗vCPU(占用两个物理线程,也就是一个物理核心)和4 GB内存,运行Ubuntu 12.04 AMD64 Server操作系统。在这个测试中没有对操作系统、文件系统、NFS、KVM等等进行任何性能调优。
  从如上测试结果可以看出,在没有进行任何性能调优的情况下,在单线程CPU性能方面,宿主机 >> 本地磁盘上的虚拟机 >> NFS服务上的虚拟机;在多线程CPU性能方面,宿主机 >> 本地磁盘上的虚拟机 = NFS服务上的虚拟机。需要注意的是,在多线程测试结果方面,宿主机所占的优势完全是由于宿主机比虚拟机多占用了两个物理线程,也就是一个物理核心。可以认为,在如上所述测试中,物理机和虚拟机的CPU性能基本上是一致的,虚拟化基本上没有导致CPU性能损失。
  (2)文件IO性能测试
  我们使用iozone来进行文件IO性能测试。iozone性能测试结果表示的是文件IO的吞吐量(KBps),但是通过吞吐量可以估算出IOPS。在如下命令中,我们评估的是以256K为数据块大小对文件进行写、重写、读、重读、随机读、随机写性能测试,在测试过程当中使用/io.tmp作为临时测试文件,该测试文件的大小是4 GB。需要注意的是,命令中所指定的测试文件是带路径的,因此我们可以测试同一虚拟机上不同文件系统的性能。例如我们通过NFS将某一网络共享文件系统挂载到虚拟机的/mnt目录,那么我们可以将该测试文件的路径设定为/mnt/io.tmp。
  cd ~/iozone3_414/src/current
  ./iozone -Mcew -i0 -i1 -i2 -s4g -r256k -f /io.tmp
  下面是一个可供参考的测试结果。在这个测试中使用了两台物理机,每台物理机各配置一颗Intel Core i3 540 @ 3.07 GHz (双核四线程),16 GB内存(DDR3 @ 1333 MHz),一块Seagate ST2000DL003-9VT1硬盘(SATA,2TB,5900RPM),运行Ubuntu 10.04 AMD64 Server操作系统,使用的文件系统为ext4,使用的Hypervisor为KVM(qemu-kvm-0.12.3)。我们分别测试了宿主机、NFS、磁盘映像以文件格式(RAW格式,没有启用virtio)存储在本地磁盘上的虚拟机、磁盘映像以文件格式(RAW格式,没有启用virtio)存储在NFS上的虚拟机、以及从虚拟机内部挂载宿主机NFS服务(虚拟网卡启用了virtio)的磁盘IO性能。虚拟机的配置为2 颗vCPU(占用两个物理线程,也就是一个物理核心)和4 GB内存,运行Ubuntu 12.04 AMD64 Server操作系统。在这个测试中没有对操作系统、文件系统、NFS、KVM等等进行任何性能调优。
  从如上测试结果可以看出,在如上所述特定测试场景中,在文件IO性能方面,宿主机 > NFS > 虚拟机中的NFS > 本地磁盘上的虚拟机 >NFS服务上的虚拟机。值得注意的是,即使是从虚拟机中挂载NFS服务,其文件IO性能也远远超过本地磁盘上的虚拟机。
  [特别说明]需要注意的是,当我们说文件(或者磁盘)IO性能的时候,我们指的通常是应用程序(例如iozone)进行文件读写操作时所看到的IO性能。这个性能通常是与系统相关的,包括了多级缓存(磁盘自身的缓存机制、操作系统的缓存机制)的影响,而不仅仅是磁盘本身。利用iozone进行文件IO性能测试时,测试结果与主机的内存大小、测试数据块的大小、测试文件的大小都有很大的关系。如果要全面地描述一个特定系统(CPU、内存、硬盘)的文件IO性能,往往需要对测试数据块的大小和测试文件的大小进行调整,进行一系列类似的测试并对测试结果进行全面分析。本文所提供的仅仅是一个快速测试方法,所提供的测试参数并没有针对任何特定系统进行优化,仅仅是为了说明iozone这个工具的使用方法。如上所述之测试数据,仅仅在如上所述之测试场景下是有效的,并不足以定性地说明任何虚拟化场景下宿主机和虚拟机的文件IO性能差异。建议读者在掌握了iozone这个工具的使用方法的基础上,对被测试对象进行更加全面的测试。(感谢saphires网友的修改建议。)
  (3)内存性能测试
  我们使用mbw来测试虚拟机的内存性能。mbw通常用来评估用户层应用程序进行内存拷贝操作所能够达到的带宽(MBps)。
  mbw 128
  下面是一个可供参考的测试结果。在这个测试中使用了两台物理机,每台物理机各配置一颗Intel Core i3 540 @ 3.07 GHz (双核四线程),16 GB内存(DDR3 @ 1333 MHz),一块Seagate ST2000DL003-9VT1硬盘(SATA,2TB,5900RPM),运行Ubuntu 10.04 AMD64 Server操作系统,使用的文件系统为ext4,使用的Hypervisor为KVM(qemu-kvm-0.12.3),虚拟机运行Ubuntu 12.04 AMD64 Server操作系统。我们分别测试了宿主机、磁盘映像以文件格式(RAW格式,没有启用virtio)存储在本地磁盘上的虚拟机、磁盘映像以文件格式(RAW格式,没有启用virtio)存储在NFS上的虚拟机的内存性能。虚拟机的配置为2 颗vCPU(占用两个物理线程,也就是一个物理核心)和4 GB内存。在这个测试中没有对操作系统、文件系统、NFS、KVM等等进行任何性能调优。
  从如上测试结果可以看出,在没有进行任何性能调优的情况下,宿主机、本地磁盘上的虚拟机、NFS服务上的虚拟机在内存性能方面基本上是一致的,虚拟化基本上没有导致内存性能损失。


 (4)网络带宽测试
  我们使用iperf来测试虚拟机之间的网络带宽(Mbps)。测试方法是在一台虚拟机上运行iperf服务端,另外一台虚拟机上运行iperf客户端。假设运行服务端的虚拟机的IP地址是192.168.1.1,运行客户端的虚拟机的IP地址是192.168.1.2。
  在服务端执行如下命令:
  iperf -s
  在客户端执行如下命令:
  iperf -c 192.168.1.1
  测试完成后,在客户端会显示两台虚拟机之间的网络带宽。
  下面是一个可供参考的测试结果。在这个测试中使用了两台物理机,每台物理机各配置一颗Intel Core i3 540 @ 3.07 GHz (双核四线程),16 GB内存(DDR3 @ 1333 MHz),一块Seagate ST2000DL003-9VT1硬盘(SATA,2TB,5900RPM),运行Ubuntu 10.04 AMD64 Server操作系统,使用的文件系统为ext4,使用的Hypervisor为KVM(qemu-kvm-0.12.3)。我们分别测试了宿主机之间、宿主机与虚拟机之间、虚拟机与虚拟机之间的内网带宽。虚拟机的配置为2 颗vCPU(占用两个物理线程,也就是一个物理核心)和4 GB内存。虚拟机的配置为2 颗vCPU(占用两个物理线程,也就是一个物理核心)和4 GB内存,运行Ubuntu 12.04 AMD64 Server操作系统。在这个测试中没有对操作系统、文件系统、NFS、KVM等等进行任何性能调优,但是虚拟机的网卡启用了virtio。
  从如上测试结果可以看出,宿主机之间的内网带宽接近内网交换机的极限。在启用了virtio的情况下,宿主机与虚拟机之间内网带宽有小幅度的性能损失,基本上不会影响数据传输能力;虚拟机与虚拟机之间的内网带宽有接近15%的损失,对数据传输能力影响也不是很大。
  (5)数据库性能测试
  postgresql是一个著名的开源数据库系统。在MySQL被Sun 公司收购并进一步被Oracle公司收购之后,越来越多的公司正在从MySQL迁移到postgresql。pgbench是一个针对postgresql的性能测试工具,其测试结果接近于TPC-B。pgbench的优点之一在于它能够轻易地进行多线程测试,从而充分利用多核处理器的处理能力。
  在虚拟机上以postgres用户登录:
  su -l postgres
  将/usr/lib/postgresql/9.1/bin加入到路径PATH当中。
  创建测试数据库:
  createdb pgbench
  初始化测试数据库:
  pgbench -i -s 16 pgbench
  执行单线程测试:
  pgbench -t 2000 -c 16 -U postgres pgbench
  执行多线程测试,在下面的命令中将N替换为虚拟机的vCPU数量:
  pgbench -t 2000 -c 16 -j N -U postgres pgbench
  下面是一个可供参考的测试结果。在这个测试中使用了两台物理机,每台物理机各配置一颗Intel Core i3 540 @ 3.07 GHz (双核四线程),16 GB内存(DDR3 @ 1333 MHz),一块Seagate ST2000DL003-9VT1硬盘(SATA,2TB,5900RPM),运行Ubuntu 10.04 AMD64 Server操作系统,使用的文件系统为ext4,使用的Hypervisor为KVM(qemu-kvm-0.12.3),虚拟机运行Ubuntu 12.04 AMD64 Server操作系统。我们分别测试了宿主机、磁盘映像以文件格式(RAW格式,没有启用virtio)存储在本地磁盘上的虚拟机、磁盘映像以文件格式(RAW格式,没有启用virtio)存储在NFS上的虚拟机的数据库性能。虚拟机的配置为2 颗vCPU(占用两个物理线程,也就是一个物理核心)和4 GB内存,运行Ubuntu 12.04 AMD64 Server操作系统。在这个测试中没有对操作系统、文件系统、NFS、KVM等等进行任何性能调优。
  从如上测试结果可以看出,在没有进行任何性能调优的情况下,在数据库性能方面,宿主机 >> 本地磁盘上的虚拟机 >> NFS服务上的虚拟机。

posted @ 2014-10-30 10:28 顺其自然EVO 阅读(677) | 评论 (0)编辑 收藏

JMS性能测试方案

JMS综述
  1、相关概念
  1)JMS
  jms即Java消息服务(Java Message Service) 是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。Java消息服务是一个与具体平台无关的API,绝大多数MOM提供商都对JMS提供支持,它提供标准的产生、发送、接收消息的接口简化企业应用的开发。是一组接口和相关语义的集合,定义了JMS客户端如何获取企业消息产品的功能。JMS并不是一个MOM。它是一个API,抽象了客户端和MOM的交互,就像JDBC抽象与数据库的交互一样。
  2)MOM
  消息中间件MOM的设计原理就是作为消息发送者和接收者的中间人。这个中间人提供了一个高级别的解耦,实现应用间的交互。 在一个较高级别看,消息就是一个商业信息单元,它通过MOM从一个应用发送到另一个应用。应用使用目标(destinations)来发送和接收消息。消息将被投递到destinations,然后发送给连接或订阅该destinations的接收者。这个机制能够解耦消息的发送者和接收者,因为它们在发送或接收消息的时候并不需要同时连接ActiveMQ。发送者不了解接收者,接收者也不了解发送者。这个机制就叫做异步消息传送。
  3)MQ
  MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过写和检索出入列队的针对应用程序的数据(消息)来通信,而无需专用连接来链接它们。消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。其中较为成熟的MQ产品有IBMWEBSPHERE MQ。
  MQ的消费-生产者模型的一个典型的代表,一端往消息队列中不断的写入消息,而另一端则可以读取或者订阅队列中的消息。MQ和JMS类似,但不同的是JMS是SUN JAVA消息中间件服务的一个标准和API定义,而MQ则是遵循了AMQP协议的具体实现和产品。JMS是一个用于提供消息服务的技术规范,它制定了在整个消息服务提供过程中的所有数据结构和交互流程。而MQ则是消息队列服务,是面向消息中间件(MOM)的最终实现,是真正的服务提供者;MQ的实现可以基于JMS,也可以基于其他规范或标准。支持JMS的开源MQ目前选择的最多的是ActiveMQ。其他开源JMS供应商:jbossmq(jboss 4)、jboss messaging (jboss 5)、joram、openjms、mantamq、ubermq、SomnifugiJMS等等。
  4)SOAP与JMS
  SOAP使用RPC(远程过程调用)和消息传递来建立通信服务,SOAP RPC定义了用于表示远程过程调用和应答的协议。SOAP协议本身仅仅定义了消息的交换结构,它可以和许多现存因特网协议结合在一起使用,其中包括超文本传输协议( HTTP),多用途网际邮件扩充协议(MIME),Java 消息服务(JMS)以及简单邮件传输协议(SMTP)等。目前与SOAP应用最为广泛的是HTTP协议和JMS协议,而与之相对应的两种应用就是SOAP Over HTTP和SOAP Over JMS。
  2、JMS体系结构元素
  JMS提供者(JMS provider):JMS接口的实现。
  JMS客户:生产或消费基于消息的Java的应用程序或对象。
  JMS生产者:创建并发送消息的JMS客户。
  JMS消费者:接收消息的JMS客户。
  JMS消息:包括可以在JMS客户之间传递的数据的对象
  JMS队列:一个容纳那些被发送的等待阅读的消息的区域。队列暗示,这些消息将按照顺序发送。一旦一个消息被阅读,该消息将被从队列中移走。
  JMS主题:一种支持发送消息给多个订阅者的机制。
  JMS提供商:JMS规范实现厂商
  JMS管理对象:预先配置好的用于JMS客户端的JMS对象。如:ConnectionFactory--这个对象用于客户端来创建和提供商的连接,Destination--这个对象用于客户端来指定发送消息的目的地(Queue或  Topic),也是接收消息的来源。被管理对象被管理员放置在JNDI命名空间。JMS客户端通常在它的文档中注上它要求的JMS被管理对象和这些对象的JNDI名字应当如何提供给它。
  JMS Domain:JMS定义了两种域模型,一种是PTP(point-to-point)即点对点消息传输模型,一种是pub/sub(publish-subscribe)即发布订阅模型。
3、JMS接口
  JMS支持两种消息类型PTP和Pub/Sub,分别称作:PTP Domain 和Pub/Sub Domain,这两种接口都继承统一的JMS父接口。JMS基于一系列通用的消息概念,每个JMS消息域—PTP和Pub/Sub—也为这些概念定义了各自的接口集。JMS客户端程序员使用这些接口来创建他们的客户端程序。JMS主要接口如下:
  Destination:消息的目的地,封装了消息目的地标识的被管理对象。
  Session:一个用于发送和接收消息的单线程上下文。
  MessageProducer(生产者): 由Session对象创建的用来发送消息的对象。
  MessageConsumer(消费者):由Session对象创建的用来接收消息的对象。
  接口之间的关系如下:
  (JMS应用)发送端的标准流程是:创建连接工厂>创建连接>创建session>创建发送者>创建消息体>发送消息到Destination(queue或topic)。
  接收端的标准流程是:创建连接工厂>创建连接>创建session>创建接收者>创建消息监听器监听某Destination的消息>获取消息并执行业务逻辑
  4、JMS消息
  消息是JMS中的一种类型对象,由两部分组成:消息头和消息体(或分三部分:消息头、属性、消息体)。消息头由路由信息以及有关该消息的元数据组成。消息体则携带着应用程序的数据或有效负载。
  1)消息头(Header):消息头包含消息的识别信息和路由信息,标准的JMS消息头包含以下属性:
  JMSDestination:消息发送的目的地。
  JMSDeliveryMode:传递模式,有两种模式: PERSISTENT和NON_PERSISTENT,PERSISTENT表示该消息一定要被送到目的地,否则会导致应用错误。NON_PERSISTENT表示偶然丢失该消息是被允许的,这两种模式使开发者可以在消息传递的可靠性和吞吐量之间找到平衡点。标记为NON_PERSISTENT的消息最多投递一次,而标记为PERSISTENT的消息将使用暂存后再转送的机理投递。如果一个JMS服务离线,那么持久性消息不会丢失但是得等到这个服务恢复联机时才会被传递。所以默认的消息传递方式是非持久性的。
  JMSExpiration:消息过期时间,等于QueueSender的send方法中的timeToLive值或TopicPublisher的publish方法中的timeToLive值加上发送时刻的GMT时间值。如果timeToLive值等于零,则JMSExpiration被设为零,表示该消息永不过期。如果发送后,在消息过期时间之后消息还没有被发送到目的地,则该消息被清除。
  JMSPriority:消息优先级,从0-9 十个级别,0-4是普通消息,5-9是加急消息。JMS不要求JMS Provider严格按照这十个优先级发送消息,但必须保证加急消息要先于普通消息到达。
  JMSMessageID:唯一识别每个消息的标识,由JMS Provider产生。
  JMSTimestamp:一个消息被提交给JMS Provider到消息被发出的时间。
  JMSCorrelationID:用来连接到另外一个消息,典型的应用是在回复消息中连接到原消息。
  JMSReplyTo:提供本消息回复消息的目的地址。
  JMSType:消息类型的识别符。
  JMSRedelivered:如果一个客户端收到一个设置了JMSRedelivered属性的消息,则表示可能该客户端曾经在早些时候收到过该消息,但并没有签收(acknowledged)。
  除了消息头中定义好的标准属性外,JMS提供一种机制增加新属性到消息头中,这种新属性包含以下几种:应用需要用到的属性、消息头中原有的一些可选属性、JMS Provider需要用到的属性。
 2)消息体:JMS API定义了5种消息体格式,也叫消息类型,你可以使用不同形式发送接收数据并可以兼容现有的消息格式,下面描述这5种类型:
  TextMessage:java.lang.String对象,如xml文件内容
  MapMessage:名/值对的集合,名是String对象,值类型可以是Java任何基本类型
  BytesMessage:字节流
  StreamMessage:Java中的输入输出流
  ObjectMessage:Java中的可序列化对象
  Message:没有消息体,只有消息头和属性
  3)消息可靠性
  在上面谈及消息体格式定义中,有个字段JMSDeliveryMode用来表示该消息发送后,JMS提供商应该怎么处理消息。PERSISTENT(持久化)的消息在JMS服务器中持久化。接收端如果采用点对点的queue方式或者Durable Subscription(持久订阅者)方式,那么消息可保证只且只有一次被成功接收。NON_PERSISTENT(非持久化)的消息在JMS服务器关闭或宕机时,消息丢失。根据发送端和接收端采用的方式,列出如下可靠性表格,以作参考。
  注意:以下的可靠性不包括JMS服务器由于资源关系,造成的消息不能持久化等因素引起的不可靠(该类不可靠应该是JMS提供商或硬件引起的的资源和处理能力的极限问题,应该由管理人员解决)。也不包括消息由于超时时间造成的销毁丢失。
  消息发送端         消息接收端                                      可靠性及因素
  PERSISTENT     queue receiver/durable subscriber      消费一次且仅消费一次。可靠性最好,但是占用服务器资源比较多。
  PERSISTENT     non-durable subscriber         最多消费一次。这是由于non-durable subscriber决定的,如果消费端宕机或其他问题导致与JMS服务器断开连接,等下次再联上JMS服务器时消息不保留。
  NON_PERSISTENT    queue receiver/durable subscriber     最多消费一次。这是由于服务器的宕机会造成消息丢失
  NON_PERSISTENT    non-durable subscriber     最多消费一次。这是由于服务器的宕机造成消息丢失,也可能是由于non-durable subscriber的性质所决定
  4)消息的优先级
  虽然JMS规范并不需要JMS供应商实现消息的优先级路线,但是它需要递送加快的消息优先于普通级别的消息。JMS定义了从0到9的优先级路线级别,0是最低的优先级而9则是最高的。更特殊的是0到4是正常优先级的变化幅度,而5到9是加快的优先级的变化幅度。举例来说:
  topicPublisher.publish (message, DeliveryMode.PERSISTENT, 8, 10000); //Pub-Sub
  或 queueSender.send(message,DeliveryMode.PERSISTENT, 8, 10000);//P2P
  这个代码片断,有两种消息模型,映射递送方式是持久的,优先级为加快型,生存周期是10000 (以毫秒度量)。如果生存周期设置为零,这则消息将永远不会过期。当消息需要时间限制否则将使其无效时,设置生存周期是有用的。
  5)消息的通知确认
  在客户端接收了消息之后,JMS服务怎样有效确认消息是否已经被客户端接收呢?
  Session session=connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
  这段代码创建一个非事务性的session,并采用auto_acknowledge方式通知JMS服务器。如果采用事务性session时,通知会伴随session的commit/rollback同时发送通知。在我们采用非事务session时,有三种通知方式。
  通知方式                   效果
  DUPS_OK_ACKNOWLEDGE session     延迟通知。如果JMS服务器宕机,会造成重复消息的情况。程序必须保证处理重复消息而不引起程序逻辑的混乱。
  AUTO_ACKNOWLEDGE           当receive或MessageListener方法成功返回后自动通知。
  CLIENT_ACKNOWLEDGE           客户端调用消息的acknowledge方法通知
  5、PTP模型
  点对点(Point- to-Point)消息传送使用的目标是队列。通过使用队列,消息可以被异步或同步地发送和接收。每一条到达队列的消息将会被投递到单独一个消费者一次,并且只有一次。这就好像两个人之间的邮件发送。消费者可以通过MessageConsumer.receive()方法同步地接收消息或使用 MessageConsumer.setMessageListener()方法注册一个MessageListener实现来异步地接收消息。队列保存所有的消息直到它们被投递出去或过期。
  JMS PTP模型中的主要概念和对象:
  Queue:由JMS Provider管理,队列由队列名识别,客户端可以通过JNDI接口用队列名得到一个队列对象。
  TemporaryQueue:由QueueConnection创建,而且只能由创建它的QueueConnection使用。
  QueueConnectionFactory:客户端用QueueConnectionFactory创建QueueConnection对象。
  QueueConnection:一个到JMS PTP provider的连接,客户端可以用QueueConnection创建QueueSession来发送和接收消息。
  QueueSession:提供一些方法创建QueueReceiver 、QueueSender、QueueBrowser和TemporaryQueue。如果在QueueSession关闭时,有一些消息已经被收到,但还没有被签收(acknowledged),那么,当接收者下次连接到相同的队列时,这些消息还会被再次接收。
  QueueReceiver:客户端用QueueReceiver接收队列中的消息,如果用户在QueueReceiver中设定了消息选择条件,那么不符合条件的消息会留在队列中,不会被接收到。
  QueueSender:客户端用QueueSender发送消息到队列。
  QueueBrowser:客户端可以QueueBrowser浏览队列中的消息,但不会收走消息。
  QueueRequestor:JMS提供QueueRequestor类简化消息的收发过程。QueueRequestor的构造函数有两个参数:QueueSession和queue,QueueRequestor通过创建一个临时队列来完成最终的收发消息请求。
  可靠性(Reliability):队列可以长久地保存消息直到接收者收到消息。接收者不需要因为担心消息会丢失而时刻和队列保持激活的连接状态,充分体现了异步传输模式的优势。
  可以看到,一个或多个生产者发送消息,消息m2先抵达了queue,然后m1也发出了,并一同存在于一个先进先出的queue里面。消费者也存在一个或多个,对queue里的消息进行消费。但一个消息只会被的一个消费者消费且仅消费一次。
 6、PUB/SUB模型
  JMS Pub/Sub模型定义了如何向一个内容节点发布和订阅消息,这些节点被称作主题(topic)。主题可以被认为是消息的传输中介,发布者(publisher)发布消息到主题,订阅者(subscribe)从主题订阅消息。主题使得消息订阅者和消息发布者保持互相独立,不需要接触即可保证消息的传送。
  JMS Pub/Sub 模型中的主要概念和对象:
  订阅(subscription):消息订阅分为非持久订阅(non-durable subscription)和持久订阅(durable subscrip-tion),非持久订阅只有当客户端处于激活状态,也就是和JMS Provider保持连接状态才能收到发送到某个主题的消息,而当客户端处于离线状态,这个时间段发到主题的消息将会丢失,永远不会收到。持久订阅时,客户端向JMS注册一个识别自己身份的ID,当这个客户端处于离线时,JMS Provider会为这个ID保存所有发送到主题的消息,当客户再次连接到JMS Provider时,会根据自己的ID得到所有当自己处于离线时发送到主题的消息。
  Topic:主题由JMS Provider管理,主题由主题名识别,客户端可以通过JNDI接口用主题名得到一个主题对象。JMS没有给出主题的组织和层次结构的定义,由JMS Provider自己定义。
  TemporaryTopic:临时主题由TopicConnection创建,而且只能由创建它的TopicConnection使用。临时主题不能提供持久订阅功能。
  TopicConnectionFactory:客户端用TopicConnectionFactory创建TopicConnection对象。
  TopicConnection:TopicConnection是一个到JMS Pub/Sub provider的连接,客户端可以用TopicConnection创建TopicSession来发布和订阅消息。
  TopicSession:TopicSession提供一些方法创建TopicPublisher、TopicSubscriber、TemporaryTopic 。它还提供unsubscribe方法取消消息的持久订阅。
  TopicPublisher:客户端用TopicPublisher发布消息到主题。
  TopicSubscriber:客户端用TopicSubscriber接收发布到主题上的消息。可以在TopicSubscriber中设置消息过滤功能,这样,不符合要求的消息不会被接收。
  Durable TopicSubscriber:如果一个客户端需要持久订阅消息,可以使用Durable TopicSubscriber,TopSession提供一个方法createDurableSubscriber创建Durable TopicSubscriber对象。
  恢复和重新派送(Recovery and Redelivery):非持久订阅状态下,不能恢复或重新派送一个未签收的消息。只有持久订阅才能恢复或重新派送一个未签收的消息。
  TopicRequestor:JMS提供TopicRequestor类简化消息的收发过程。TopicRequestor的构造函数有两个参数:TopicSession和topic。TopicRequestor通过创建一个临时主题来完成最终的发布和接收消息请求。
  可靠性(Reliability):当所有的消息必须被接收,则用持久订阅模式。当丢失消息能够被容忍,则用非持久订阅模式。
  在pub/sub消息模型中,消息被广播给所有订阅者。订阅者可以同步接收消息也可以异步接收消息,消息的同步接收是指客户端主动去接收消息,消息的异步接收是指当消息到达时,主动通知客户端。
  使用JMeter测试JMS
  JMeter是Apache开发的一款小巧易用的开源性能测试工具,由java语言开发。JMeter不仅免费开源而且功能强大、易于扩展,如果有一定Java开发基础的话还可以在JMeter上做扩展开发新的插件等,几乎能满足各种性能测试需求。JMeter中使用Sampler元件(取样器)来模拟各种的类型的请求数据格式,类似于LR中的协议(比LR中的协议概念更广),如:http、ftp、soap、tcp等等。JMeter中支持的JMS Point-to Point、JMS Publisher和JMS Subscriber分别用于发送JMS的PTP消息和PUB/SUB消息,因此可以选择使用JMeter来测试JMS。
  MOM(消息中间件)作为消息数据交换的平台,也是影响应用执行效率的潜在环节。在Java程序中,是通过JMS与MOM进行交互的。作为Java实现的性能测试工具JMeter也能使用JMS对应用的消息交换和相关的数据处理能力进行测试。在整个测试过程中,JMeter测试的重点是消息的产生者和消费者的能力,而不是MOM本身。JMeter虽然能使用JMS对MOM进行测试,但是它本身并没有提供JMS需要使用的包(实现类)。因此在使用JMeter测试JMS时需要使用到具体的MOM的相关jar包。以下结合流行的开源消息中间件ActiveMQ来演示如何使用JMeter来实现对JMS的测试。
  1、安装并启动ActiveMQ服务
  2、测试前的准备
  使用JMeter进行压力测试时,所有的JMeter依赖的包需要复制到%JMETER_HOME%/lib目录下。对于ActiveMQ来说,就是复制%ACTIVEMQ_HOME%/lib目录下jar包,可根据实际情况来考虑是否复制。JMeter在测试时使用了JNDI,为了提供JNDI提供者的信息,需要提供jndi.properties。同时需要将jndi.properties放到JMeter的%JMETER_HOME%/lib和%JMETER_HOME%/bin目录中,还需要将jndi.properties与%JMETER_HOME%/bin目录下的ApacheJMeter.jar打包在一起。对于ActiveMQ,jndi.properties的演示内容如下:
  1 #java.naming.factory.initial = org.activemq.jndi.ActiveMQInitialContextFactory
  2 java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory
  3 java.naming.provider.url = tcp://localhost:61616
  4
  5 #指定connectionFactory的jndi名字,多个名字之间可以逗号分隔。
  6 #以下为例:
  7 #对于topic,使用(TopicConnectionFactory)context.lookup("connectionFactry")
  8 #对于queue,(QueueConnectionFactory)context.lookup("connectionFactory")
  9 connectionFactoryNames = connectionFactory
  10
  11 #注册queue,格式:
  12 #queue.[jndiName] = [physicalName]
  13 #使用时:(Queue)context.lookup("jndiName"),此处是MyQueue
  14 queue.MyQueue = example.MyQueue
  15
  16 #注册topic,格式:
  17 # topic.[jndiName] = [physicalName]
  18 #使用时:(Topic)context.lookup("jndiName"),此处是MyTopic
  19 topic.MyTopic = example.MyTopic
  3、测试JMS的PTP模型
  对于点对点模型,JMeter只提供了一种Sampler:JMS Point-to-Point。如图所示建立测试计划:
  QueueConnection Factory:连接工厂,输入jndi配置文件中配置的connectionFactory
  JNDI name Request queue:请求队列名,输入jndi配置文件中配置的MyQueue
  JNDI name Receive queue:接收队列名,输入jndi配置文件中配置的MyQueue
  Content:消息内容,比如输入:this is a test
  Initial Context Factory:输入org.apache.activemq.jndi.ActiveMQInitialContextFactory
  Provider URL:提供者URL,即安装的ActiveMQ的服务地址tcp://yourIP:61616
  运行调试时通过监视器元件查看是否发送成功,如下说明发送成功:
 4、测试JMS的PUB/SUB模型
  在实际测试时,发布者和订阅者并不是需要同时(异步)出现的。比如有时我们可能想测试单位时间内消息发布者的消息产生量,此时就不需要消息发布者,只需要订阅者就可以了。本例为了说明这两种Sampler的使用,建立两个JMeter实例分别用于发送和接收消息。
  1)首先新建如下订阅者的测试计划:
  勾选使用jndi配置文件,并分别输入jndi中配置的连接工厂和目的地名称,如上图所示,点击运行下的启动,使用消息消费者处于接收状态。
  2)然后新建如下发布者的测试计划:
  勾选使用jndi配置文件,并分别输入jndi中配置的连接工厂和目的地名称以及要发送的消息内容,此处为:this is a pubish test,如上图所示,点击运行下的启动,以发送消息,查看监视器元件检查消息是否发送成功,如下说明发送成功:
  检查消息消费者是否接收到消息,如下说明接收成功:
  上面已完成了JMeter对JMS的基本测试演示,实际测试时可能需要根据实际的场景选择合适的取样器,添加其他测试元件来建立和增强测试计划,根据真实测试的中间件拷贝依赖包以及配置jndi以完成JMS应用的性能测试。

posted @ 2014-10-30 10:18 顺其自然EVO 阅读(428) | 评论 (0)编辑 收藏

Shift Left性能测试-不一样的测试方法

 开始着手全球性IT转型项目对于任何组织来说都是一件即兴奋又富有挑战的事情。当然,降低失败风险是整个项目的主要目标之一。而测试是能明显帮助降低失败几率的活动之一。
  本文介绍了与传统多用户性能测试所不同的测试方法;尽管所使用的工具相同,但该方法结合了现代数据可视化技术,从而早早就能对那些可能存在有“沉睡着的”性能问题的特定位置及应用程序区域有所洞察。
  大多数项目会首先专注于功能,然后才是其它。使用类似HP LoadRunner或Neotys Neoload这类测试工具的多用户性能测试往往属于测试循环后期才会发生的活动。很多时候会与UAT并行发生,而这时新系统已经暴露给终端用户了。因此在性能测试时发现性能问题的几率很高,修复的几率却很低。因为这种情况下,通常距离上线时间已所剩无几。
  多用户性能测试通常发生于项目后期的原因有多种,根据项目的不同而不同。以下两个原因最为常见:
  1.多用户性能测试要求工具和自动化。自动化性能测试脚本所需的资源只有在性能测试即将开始时才有望存在,即应用程序达到“稳定”的开发状态时。假如自动化一个性能测试脚本需要2天的话,那么拥有多个测试脚本(比如:10至20个)就要花费大量的时间或人力。为了不破坏当前在性能测试脚本开发上所花费的资源,该阶段不允许修改应用程序。所造成的结果就是:开发阶段的任何延迟或需要对代码进行大量的修改都将进一步延误性能测试,这给执行带来了风险,也不能及时提供相应价值。
  2.多用户性能测试需要一个类产品环境。尤其是处于IT转型的项目,这样的环境不一定在项目初期就存在,需要时间、精力和金钱去构建。但与之竞争的是早期测试周期中所有其它必需的对测试环境的配置和那些“真正办事的”功能。对项目而言,绝对需要类产品环境的最早一刻是测试部署时(即彩排时刻)。而这时要想让性能测试对项目成果产生正面影响已为时过晚。
  作为降低风险的活动,性能测试是绝对必要的。真正的挑战在于如何以不同方式进行,这样可以在有更多时间和预算时就能解决与性能相关的问题。性能测试应在测试生命周期内更频繁地被执行,同时与主要发布周期相互协调,从而提供更好的投资回报,并不断地帮助降低项目风险。
  以下这些目标很可能与大部分IT转型项目的目标类似:
  1.现代化 全球IT通过更新ERP和CRM应用程序到最新版本,为未来创新铺平了道路。
  2.合理化 优化应用程序以降低成本和复杂性
  3.集中化 集中化IT基础架构以降低成本和提高灵活性
  本文所要说明的方法曾被一个处于IT转型的项目采用,该项目运行于一个中等规模企业,该企业在全球范围内运营,世界各地的办事处数量也在不断扩大。其通过标准的客户关系管理系统(CRM)和企业资源规划(ERP)应用程序, 在本地办公室内面对面地处理与客户的业务。
  这两个应用程序的共同关键属性是显示大量数据给用户的同时,执行关键业务流程。此外,这些面向客户的业务流程还需要输入大量数据集(数百个记录/业务流程),然后在彼此上层处理。在以前使用大量数据集的测试业务流程往往只计划发生于用户验收测试(UAT)。其主要原因是:想在允许时间内覆盖所有必需测试集而手动输入数据的话,太费时间。数据迁移工作流被指定来为UAT传输这些数据,但是由于延迟,我们往往要等到UAT开始时才能期望用得上这些数据。
  之前版本的CRM解决方案已经报告存在性能问题。当时该CRM已经集中化,并应用于世界各地的多个办公室。这些性能问题因地点而异,分布于不同的功能块;而且是由终端客户报告出来的,没有具体的测试或时间可供参考。
  相反,之前的ERP解决方案是独立安装于各个地区或国家的,目前还没报告有性能问题。但是集中运行这两个应用程序的话,不由得让人担忧其性能,尤其在处理数据输入、扫描和打印等活动时。
  可拓展性测试虽然是多用户性能测试的一个关键点,但却算不上该项目的关注点。以市场为导向的标准软件在实施时尽量地减少定制,并在产品环境中配置大小正好的基础设施服务器。
  非功能性需求被定义为该项目的一部分,却需要被验证。该组织多年前曾购买过HP LoadRunner作为性能测试的首选工具。但由于预算的限制,后来并未在测试工具上做进一步的投资。
  综合考虑各方面的限制和需求,该项目将以下这些定义为性能测试的主要目标:
  1.度量 度量来自不同办公地点的应用程序的性能。
  2.对比 与非功能需求的性能结果进行对比。
  3.改进 为潜在的改进提供建议。
  该解决方案从单一用户角度出发进行性能测试。对关键业务流程的测试将在数个月内以真实的、自动化的形式在世界各主要地点进行,同时还覆盖了各主要发布周期。现代可视化技术将显著地减少分析及诠释测试结果,还有呈现到项目管理团队的时间。该单一用户性能测试方法相比于“传统的”多用户性能测试有以下众多优点:
  1.不需要类似产品一样的环境,可以使用任一现有测试环境。
  2.其迭代方法允许性能测试脚本随着应用程序的发展而不断成熟,频繁的使用带来了良好的投资回报。与其冒着无法及时交付测试结果的极大风险而在短期内将大量预算花费在聘请众多性能测试脚本编写者上,这些费用大可以用于长期聘请一两位性能测试脚本编写者。
  3.并非所有性能测试脚本都要同时准备好,并运行。
  4.无需工作负载配置文件。
  5.一旦类产品环境可用,自动化脚本可重用于多用户性能测试。
  6.相比于手动测试,由于数据创建是自动的,单一用户性能测试可以在业务流程中使用更多更真实的数据量。
单一用户性能测试解决方案在执行时用到以下工具和方法:
  1.资源上的限制决定了客户端的执行性能(比如:渲染时间)将不被考虑在内。这将通过在客户机上使用Profilers来完成(谷歌开发者工具),或将功能测试自动化工具结合类似WireShark等网络协议分析器。测试最初只专注于包括网络时间在内的服务器响应时间。
  2.每个办公地点都会有两个用户配有已识别好的台式机,机器上装有HP的Load Generator软件。来自同一地点的两组测量数据保证了所收集数据的正确率。如果在任何时候两台机器针对相同活动所收集的数据都相差很多,我们就可以认为是本地用户设置出了问题。这不需要额外的硬件投资,也能从真实用户地点收集到响应时间测量值,因此特别真实。在该测试中所用到的脚本也能在多用户性能测试中复用,为性能测量提供统一、可重复的方法。不需要支付其它附加的测试工具许可证费用。
  3.每个办公地点和数据中心的HP Load Generator分别以每15/1分钟频率执行性能测试脚本,确保我们不会稀里糊涂地陷入到执行多用户性能测试的陷阱中。其主要目的是将测试系统中的并发降到最低。从数据中心获取的测量数据扮演着“基准值”的角色,换句话说就是所谓的参考点。因此不同办公地点间的响应时间与“基准值”的不同可被假定为终端用户总体响应时间中与地点相关的那一部分,具体包括影响终端用户性能体验的网络延迟、路由、繁琐性及大小等等。“基准值”代表了服务器时间的具体值。根据测试环境的配置,从该测量数据中获取的结论可以用来判断是否存在与测试环境设置相关的问题。总体上的建议是测试环境应只水平地与产品环境版本进行缩放,而CPU速度、每个并发用户的内存及硬盘等输入输出速度应当与产品环境相当。这样我们就就可以很容易的假设”基准值”就是服务器的实际性能.
  4.监测网络延迟(ICMP)和路由(tracert),并将其作为标准HPLoadRunner客户端吞吐量的一部分。这三个测量值的组合允许我们评估网络、路由和带宽限制的质量。
  5.通过使用较低层的HP LoadRunner Web/HTML协议,应用程序的繁琐性将自动被记录,其影响也可评估出。而使用类似Ajax True Client协议这样较高层的HP LoadRunner协议,在检测繁琐度时则需要额外的精力和工具(比如:Wireshark或Google 开发者工具集)。
  该整体SUPT方法可以通过使用其他性能测试或类似HP Business Availability Centre(HP BAC)这样的性能监控工具以类似的方法来执行。
  为了收集有价值且有效的数据,我们在所有办公地点将所有性能测试脚本执行上一段足够长的时间。每个地点都使用两个Load Generator的策略让我们对测试结果更有自信,也帮助我们定位及解决用户在配置上的不同。
  “基准值”允许我们在不同环境上执行测试,比如:系统集成、用户验收或预产品等环境,通过对比不同地点的响应时间及相应数据中心的响应时间,我们可以区分出特定性能问题来自应用程序,还是环境或地点。
  但要想使之成为可能的先决条件是在数据中心每隔一分钟执行一遍性能测试脚本的循环。而其他所有地点则会每15分钟循环一遍(每个地点间交错开1分钟的间隔)。目的在于观察服务器和远程地点在执行相同流程时响应时间的不同,而不是让服务器超载。
  一旦结果出来,我们要面对的挑战是如何尽快有效地分析这些数据并为以下内容提供信息和分析数据:
  1.性能最差的地点。
  2.性能最差的测试脚本(业务流程)。
  3.针对非功能需求的性能(SLAs)。
  4.可被网络管理团队定位的路由和网络延迟信息。
  5.针对如何改进性能所提出的建议。
  SUPT的结果是由每个地点每一个事务响应时间而组成的大数据表。我们选择第90百分位作为响应时间的代表值。
  圆形可视化
  我们所面临的挑战是找到能快速分析这些数据的工具。查看过各种各样可视化工具及技术之后,我遇到了Mike Bostoks的“D3”项目,从那找到了圆形可视化及Circos,从而发现完成这一工作的最佳工具。
  “Circos是将数据和信息可视化的软件包。它以圆形布局可视化数据,这使得Circos成为研究事务或地点间关系的理想工具,也是展示图表的理想工具。圆形布局除了美观外,还有其它的有利因素。”
  有不少工具可让Circos更易于使用,Table Viewer tool就是其中一个,在网上就可以找到。
  建议在Linux上下载并配置Circos。第一次分析时,最简单的方式是使用这里的Table Viewer tool的在线版本。
  性能测试结果需导入到数据表中,其内容应与下图相似。数据表还需符合以下要求:
  1.无重复事务名。对于所有业务流程中相同的业务,推荐使用“S01_xx”作为惯例(比如:S01_Login)。
  2.事务或地点名中无空格。
  3.将地点作为列(“A1”,“A2”等)
  4.将HP LoadRunner事务名作为行(“da”,“db”等)。
  5.将第一列重命名为“Label”。
  6.尽量保持名字短小。
  7.将文件分割符选为“Tab”。
  单单使用Table Viewer默认在线配置就能生成令人惊喜的结果。用于在线生成图形的配置文件可以下载下来与本地安装一起使用。
  所得到的结果是类似下图。理解该图像的关键是从12点钟开始,然后顺时针查看HP LoadRunner响应时间测量值;或者参考事务(小写字母),然后逆时针查看地点(大写字母)。地点所对应的厚度是该地点所有响应时间的总和。同时生成的柱状图对进一步分析也非常有用。仅通过视觉比较,我们一眼就可以看出哪些地点受到低性能的影响,以及相对应的特定流程和步骤。
  由于事务的数量可以相当大,该图像在分析事务时信息量可能会有所减少。下一步我们需要过滤掉那些没有问题的响应时间。比如那些响应时间少于最低SLA(以5秒为例)的事务就可以被排除出去。使用Table Viewer工具的话,有两种方式可以达到这一目的。其中一种是过滤掉这些事务,但将其保留在总体计算中。
  该图像确实突出了性能最差的事务,以及它们在总体业务流程性能上所占的百分比,同时它还为理解潜在的性能改进提供了基础。
  要想在更紧凑且缩放的视图中查看相同信息的话,我们还可以将那些通过SLA的事务从总体计算中排除。
我们现在可以清楚地识别出“fa”、“ea”、“dz”和“da”事务的性能是最差的,而“A1”、“A2”和“A8”地点的性能最好,“A1”地点则是数据中心。
  现在的目标是生成网络延迟和路由的相似视图。第一步我们需要用LoadGenerator将HP LoadRunner Analysis中的从源到目的地的路由所对应的总网络延迟信息分组(Analysis工具的一个功能)。然后将这些信息导出到电子表格中。
  我们的目的在于验证网络延迟是否在预期的SLA范围之内。下图比较了网络延迟测量值和已知的从源到目的地的SLA临界值。为了了解是否有已知地点超出SLA,需要添加主机地点的信息。举个例子:如果HOST11位于欧洲,那么SLA就通过了,如果位于其它地方,则失败。
  同样每个地点的吞吐量也要与参考点进行对比,与地点的假定可用带宽及用于数据中心的实际带宽进行对比。数据中心地点的测量值将决定达到假定的接近无限带宽的可能最大值(比如:千兆以太网)。
  下一步目标是为网络管理团队获取更多的细节,我们尝试获取更多关于路由和网络延迟的详尽分解信息。该分析的基础是HP LoadRunner分析工具中的网络段延迟图(Network Segment Delay Graph)。
  桑基图
  桑基图是有向图,其箭头线的大小代表了流量大小。桑基图被用于各种流程的可视化,不限于能源和材料,是任何“从”源“到”目的地的流程定义(实际或虚拟)。桑基图将我们的注意力带到了流量最大的流程上的同时,也显示了各个流程间的流量比例,指示了“从 - 到”的流动方向。桑基图是以爱尔兰工程师Captain Matthew Henry Phineas Riall Sankey(1853-1925)的名字命名的。
  下图的创建使用了来自http://www.d3noob.org/ 的桑基图实例和从HPLoadRunnerAnalysis工具中提取的网络段延迟数据。
  生成该图像的步骤如下:
  1.下载D3noob实例文件到目录。
  2.将从HP LoadRunner Analysis工具中导出的网络段延迟数据导入到电子表格中,然后将其拷贝到“data”子目录中的“Sankey.xls”。
  3.确保网络延迟无零值,可以将0值设置为0.01或其它。
  4.确保电子表格中的标题如下所示,并将其保存为“.csv”文件。
  5.刷新本地URL就能看到如上图显示的图像。
网络可视化
  桑基图用于理解单个网络路径和延迟时特别有效。但当试图显示整个网络时,d3noob实例的局限性就暴露出来了。而我们的需求是采用一个易于使用的工具将复杂的网络图可视化。可用的工具很多,尤其在社交网络分析这方面,NodeXL是最适合这一目的的工具。
  “NodeXL是Microsoft? Excel? 2007、2010 和(可能)2013免费的开源模板,它使得网络图像探索变得轻松。有了NodeXL,我们可以在工作表中输入网络边缘列表,然后点击按钮查看图像,所有的内容都呈现在熟悉的Excel窗口里。”
  我们将所有网络延迟段信息输入到同一工具里,并期望它能帮助我们确定任意特定路由问题。NodeXL所带来的视图效果还有很多,在这里我们并没有全部采用(像节点图片等)。
  性能良好的网络段通过基于标签的“动态过滤器(Dynamic Filter)” 可以简单地过滤掉。这种情况下,该标签是网络延迟的数值表征。我们还未探索的可能性是创建源到目的地网络延迟计算的交互总值。尽管它会是个有趣的功能,但并非是必须的。从之前的分析中,我们已经有了总的源到目的地的测量值。
  为了调查正确的路由方向,可以将图像属性从未定向改成定向。
  在该实例中,图中间的“diamond”看起来比较可疑。该工具有简单的缩放功能。
  上图显示了部分通信从“E”跳转到“J”的两种路径,分别是“HH”和“II”。“II”路由的延迟要比“HH”路由高。该信息可以很容易地传递到网络管理团队,并用于项目内的沟通。我们期望网络团队能调查“diamond”存在的原因,并提供合适的解决方案。
  通过上述步骤,我们对应用程序和地点性能的理解不再是个谜团,是时候开始专注关键的性能改进了。想要理解哪个改进是关键的,性能测试结果需要与非功能需求进行对比。这可以使用带有过滤功能的Circos或带有图像和表格的Excel可视化功能来完成。
  下表显示了每个地点响应时间的分析总结。SLA列值是从表中检索出来的,用来确保SLA的简单管理,以防止任何变化。
  该总结图表可以如下蜘蛛网图来显示。
  同样的方法也需要应用到网络延迟和吞吐量SLA的测量及比较。
  现在我们所拥有的关键调查结果包括:
  1.我们知道业务流程中哪些步骤有性能问题。
  2.我们知道哪个地点有性能问题。
  3.我们知道网络延迟和带宽测量值。
  下一个步骤我们需要进一步深入获取有性能问题的业务流程详情。之前的步骤允许我们非常有效地走到这一步。
  现在我们要做的是回答以下这些问题:
  1.应用程序是否要下载多个静态对象?如果是,那么这些对象能否缓存到本地,从而避免网络下载?能否降低数量或将对象组合起来?
  2.应用程序是否繁重,其繁重性是否随着数据处理量的增加而增加?在该示例中,应用程序可以按顺序针对每个事项在服务器中调用一个更新。如果只是手动测试中的10个事项则完全没有问题,但如果是在SUPT时使用的真实数据量达到500至1000个事项的话,对性能将会有显著的影响。
  3.应用程序是否要下载或上传大型对象,比如:文档、图像等?扫描仪的设置会极大地增加扫描文件的大小,却不会显著地提高其质量。检测扫描文件的大小会明显地影响上传和下载时间。另外,带宽也会随之大幅度地增加。
  总的说来,该单用户性能测试方法的目的在于通过在全球不同内部地点内对真实数据量的使用,从而让我们对应用程序性能能有个早期的概念。使用适当的现代可视化工具能帮助我们快速地分析与性能相关的数据,并定位性能问题。对上述方法和工具的使用也确保了其结果能在项目中传递的同时,被技术或非技术人员理解。

posted @ 2014-10-30 09:27 顺其自然EVO 阅读(190) | 评论 (0)编辑 收藏

梳理非功能测试

手机端发起性能测试,两种方式:
  1. LR 11.5版本支持直接录制,用于客户端主动发起交易,服务器端返回请求
  2. websocket录制,被动接收,时刻会有监听,一旦监听到有新的东西,会主动推过来,即基于html5
  zx写脚本写两套,一个是LR录制的,一个是基于Jquery开发的。Jquery是基于JS的,通过脚本实现的。JS依赖于IE,在IE环境里执行的。模拟这个过程
  交易路径的选取原则:
  1. 按照交易路径的复杂度
  2. 交易路径的典型性
  接入端,一旦APP发布出来后,很多用户会用到,有些消耗服务器端资源,有些消耗客户端资源(关键字:websocket Android 被动 主动)
  拿着pad转的投保经理,前端提交的信息,到后端走的只是调用不同的接口,本质上走的也是http协议。接口测试就是拼报文,报文格式不同,有的是xml报文,有的是json格式。后端报文格式(atm机、柜面接入的、pos)使用8583,前端不能用,基于xml格式的,json格式。
  加密这个问题:接入端发起的是明文,然后要看是什么类型的加密:如果是封装在LR交易线里的,则自己做加解密,返回的也是明文;而对于mq这种是敏感字段加密,送过去后服务器不进行二次加密,直接对密文直接解析;因此前端需要加解密;
  1、如何测试db2数据库与中间件连接方式下,总帐凭证的保存效率:was中间件,使用的是was数据源;ibm的中间件--连接数 数据库缓存 超时时间
  2、如何监控中间件与数据库连接的并发书和事务数:连接池的连接数;数据库这块儿事务的提交数,awr方式
  B2B 使用https 就是有个设备,请求过去转一圈,LR端只需要把HTTP换成HTTPS就成
  B2C 使用http

posted @ 2014-10-30 09:25 顺其自然EVO 阅读(173) | 评论 (0)编辑 收藏

使用Office-Word的博客发布功能(测试博文)

 本人打算在博客园开博,但平时收集和整理资料都在OneNote中,又不想在写博客时还要进行复制粘贴操作,于是就想到了Microsoft Office自带的博客发布功能。在此做了一下测试,发布了此博文。
  操作说明:(本人使用的Microsoft Office 2013)
  选择要发布的OneNote页面;
  点击"文件——发送——发送到博客"
  此时会打开一个Word页面,若还没有添加帐户,则可以"注册"一个. 在弹出的对话框中选择"其它",下一步.如:
  在新建帐户页中,在API下拉列表中选择:MetaWebLog.在博客文章URL中输入:http://www.cnblogs.com/用户名/services/metaweblog.aspx,其中用户名为你博客员的用户名.输入帐户信息中填入你博客园的帐号和密码即可.如:
  这样你就完成Word对发布Blog的设置,现在你可以方便的书写博客和发布了.

posted @ 2014-10-30 09:24 顺其自然EVO 阅读(209) | 评论 (0)编辑 收藏

移动测试用例总结

 一、编写testcase的疑惑
  在编写的时候,一直都在考虑什么样的用例才是一个好的用例,如何去评价一个用例的价值?
  测试用例是在执行用例时,一个比较重要的过程,它关于一个具体的测试步骤,简单的描述输入的参数、前提条件,预期结果的输出等等,在执行的时候,实际的结果与预期结果是否想吻合;测试用例的设计、编写都是测试当中比较重要的过程;
  二、在设计用例时,testcase的设计
  按功能点分模块,还是UI界面?
  如dashboard中有八个模块,每一个模块来做一个分支处理,然后再到每个模块里面细分,突然觉得每个模块中的很多testcase都是相同的,比如一个模块中有搜索功能,另一个也有搜索功能,是否这两个模块都需要去编写testcase呢?
  对于用例标题的设计,个人习惯与用一个动宾短语去写一个testcase,可是想想又觉得你的用例是针对某一个功能而言,而并不是针对某一个操作的,试着努力去用一个名词短语表达这个用例的功能;突然觉得写用例对语文要求高,好吧,对于这种语文水平不咋地的人来说,是一种多大的折磨;
  对于手机App的测试,个人觉得是测试里面相对来说比较简单的测试,整个应用的功能都数的过来,一般要考虑的测试点有:
  a.断开网络的测试;
  b.断开Gps的测试;
  c.在操作中突然有来电;
  d.在操作中突然有短信;
  e.在应用里面,可以多次进行操作某一个功能,检查系统是否会挂掉;
  f.当然对于一个手机应用来说,用户体验是相当重要的;
  三、用例总结
  具有较高的发现错误的概率,没有多余的操作步骤,看不起既不简单也不复杂,案例是可用来重用与跟踪,确保系统能够满足功能的需求;

posted @ 2014-10-30 09:23 顺其自然EVO 阅读(206) | 评论 (0)编辑 收藏

测试用例的一般结构

  前置的有环境信息,包括硬件和软件。
  然后就是设置和前提。这里的设置,一般包括一个隐形的总体设置。这个总体设置一般在测试用例中不会说明,由自动化脚本完成。这个总体设置,一般是和demo data关联。是为所有测试用例服务的。第二个Test Case Setup, 这个Setup是测试用例的Setup, 这部分Setup, 往往是针对General Setup的修改。需要明确的在测试用例报告里面说明。
  接下来就是步骤。
  然后就是比对实际结果和预期结果的差异,分析测试用例了。
  大概就是这样。

posted @ 2014-10-30 09:23 顺其自然EVO 阅读(219) | 评论 (0)编辑 收藏

移动测试用例总结

一、编写testcase的疑惑
  在编写的时候,一直都在考虑什么样的用例才是一个好的用例,如何去评价一个用例的价值?
  测试用例是在执行用例时,一个比较重要的过程,它关于一个具体的测试步骤,简单的描述输入的参数、前提条件,预期结果的输出等等,在执行的时候,实际的结果与预期结果是否想吻合;测试用例的设计、编写都是测试当中比较重要的过程;
  二、在设计用例时,testcase的设计
  按功能点分模块,还是UI界面?
  如dashboard中有八个模块,每一个模块来做一个分支处理,然后再到每个模块里面细分,突然觉得每个模块中的很多testcase都是相同的,比如一个模块中有搜索功能,另一个也有搜索功能,是否这两个模块都需要去编写testcase呢?
  对于用例标题的设计,个人习惯与用一个动宾短语去写一个testcase,可是想想又觉得你的用例是针对某一个功能而言,而并不是针对某一个操作的,试着努力去用一个名词短语表达这个用例的功能;突然觉得写用例对语文要求高,好吧,对于这种语文水平不咋地的人来说,是一种多大的折磨;
  对于手机App的测试,个人觉得是测试里面相对来说比较简单的测试,整个应用的功能都数的过来,一般要考虑的测试点有:
  a.断开网络的测试;
  b.断开Gps的测试;
  c.在操作中突然有来电;
  d.在操作中突然有短信;
  e.在应用里面,可以多次进行操作某一个功能,检查系统是否会挂掉;
  f.当然对于一个手机应用来说,用户体验是相当重要的;
  三、用例总结
  具有较高的发现错误的概率,没有多余的操作步骤,看不起既不简单也不复杂,案例是可用来重用与跟踪,确保系统能够满足功能的需求;

posted @ 2014-10-30 09:17 顺其自然EVO 阅读(179) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 30 31 32 33 34 35 36 37 38 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜