当前位置: 首页 > news >正文

大兴手机网站建设网站建设策划 优帮云

大兴手机网站建设,网站建设策划 优帮云,浙江省建筑信息港,seo网站案例自动化测试业界主流工具 核心目标#xff1a; 主要是功能测试和覆盖率测试 业界常用主流工具 GoogleTest GoogleTest是一个跨平台的(Liunx、Mac OS X、Windows 、Cygwin 、Windows CE and Symbian ) C单元测试框架#xff0c;由google公司发布#xff0c;为在不同平台上为编…自动化测试业界主流工具 核心目标 主要是功能测试和覆盖率测试 业界常用主流工具 GoogleTest GoogleTest是一个跨平台的(Liunx、Mac OS X、Windows 、Cygwin 、Windows CE and Symbian ) C单元测试框架由google公司发布为在不同平台上为编写C测试而开发的。它提供了丰富的断言、致命和非致命判断、参数化、”死亡测试”等等。例如 测试用例本身就是一个exe工程编译之后可以直接运行非常的方便。 编写测试案例变的非常简单使用一些简单的宏如TEST让我们将更多精力花在测试用例设计上。 提供了强大丰富的断言的宏用于对各种不同检查点的检查。 提高了丰富的命令行参数对脚本运行进行一系列的设置。 pytest pytest是一个非常成熟的全功能的支持Python语言的单元自动化测试框架。简单灵活容易上手支持参数化能够支持简单的单元测试和复杂的功能测试还可以用来做selenium/appnium等自动化测试以及接口自动化测试pytest集成requests。 Mockito Mockito是GitHub上使用最广泛的Mock框架并与JUnit结合使用Mockito框架可以创建和配置mock对象。使用Mockito简化了具有外部依赖的类的测试开发 JMockit JMockit是一个用于Java语言单元测试的开源Mock工具包含了工具和API集合。Jmockit可以和junit和TestNG配合使用编写单元测试。 JMockit支持类级别整体mock和部分方法重写以及实例级别整体mock和部分mock可以mock静态方法、私有变量及局部方法。 这个工具还具有统计单元测试代码覆盖率的功能提供了三种类型的代码覆盖率如行覆盖率、路径覆盖率和数据覆盖率。 Spock Spock是一个为Groovy和Java语言应用程序来测试和规范的框架。这个框架的突出点在于它美妙和高效表达规范的语言。得益于JUnit RunnerSpock能够在大多数IDE、编译工具、持续集成服务下工作。Spock的灵感源于JUnitJMock, RSpec Groovy,Scala,Vulcans以及其他优秀的框架形态。 Junit JUnit是一个为Java编程语言设计的开源单元测试框架由 Kent Beck 和 Erich Gamma建立它是单元测试框架家族中的一个这些框架被统称为xUnitJUnit是xUnit 家族中最为成功的一个。JUnit 有它自己的 Junit 扩展生态圈多数 Java 的开发环境都已经集成了 JUnit 作为单元测试的工具。JUnit 的最新版本是JUnit 5它不再是一个单一的JAR 包而是由JUnit platform平台、JUnit Jupiter 和JUnit Vintage 这3 部分组成。 TestNG TestNG 是另一个为Java编程语言设计的开源单元测试框架是一个受JUnit和NUnit启发而来的测试框架但它引入了一些新功能使其更强大、更容易使用例如: 核心特性是多线程测试执行测试代码是否是多线程安全的; 提供注释支持; 支持数据驱动测试(使用DataProvider); 支持参数化测试; 强大的执行模型不再有TestSuite; 支持各种工具和插件(Eclipse, IDEA, Maven等…) 嵌入BeanShell以获得更多的灵活性 用于运行时和日志记录的默认JDK函数(没有依赖关系)。 Selenium Selenium也是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中就像真正的用户在操作一样。支持的浏览器包括IE、Mozilla Firefox、Mozilla Suite等。这个工具的主要功能包括测试与浏览器的兼容性——测试你的应用程序看是否能够很好得工作在不同浏览器和操作系统之上。 Spring Test Spring Test是Spring MVC自带了一个非常有用的测试框架该框架无需进行Web容器即可进行深度测试。 它是用于向Spring应用程序编写自动测试的最有用的库之一。它提供了一流的支持可以为Spring的应用程序包括MVC控制器编写单元测试和集成测试。 自动化测试 随着企业内部自动化资产的持续积累以及持续集成的推进对自动化测试的运行速度要求越来越高某些应用的自动化测试用例可能多达几千条如何加速这些自动化用例的运行速度让自动化落实到每一次版本变更和持续集成当中是一个需要解决的问题。 Squaretest **1**我使用的是idea我们先来下载一下插件File——Settings——Plugins搜索Squaretest然后install就好了插件安装完成后需要重启一下 **2**首先我们打开一个类这个类就是我们即将要作为实验的类因为Squaretest生成的单元测试方法都是只能生成public的当然这也是合理的嘛毕竟private的肯定被public调用了 **3**如果我们来手写这个类的单元测试光看都要一会下面看我操作打开你的类光标定位到代码里右击鼠标选择Generate… **4**然后你就会看到这里有两个熟悉的图标第一次的话选择第二个选项它会让你选择你一下单元测试的模板因为我已经选择过了所以我现在演示不回再弹出但后面我会告诉你怎么更改模板。 **5**选择第二项后就会弹出一个框看下面这里它自动会识别出当前类需要Mock的成员变量直接点ok **6**自动会使用类的真实目录层次在test文件夹中创建出来一个单元测试类类名就是原类名后加Test 我们只需要检查一下逻辑 稍微调整下就可以了代码覆盖率还是很高的。 Mockito Mock单元测试 添加依赖 !--mockito依赖-- dependencygroupIdorg.mockito/groupIdartifactIdmockito-core/artifactIdversion2.7.19/versionscopetest/scope /dependency !-- junit依赖 -- dependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.12/versionscopetest/scope /dependency1Mockito简单轻量级的做mocking测试的框架 2mock对象在调试期间用来作为真实对象的替代品 3mock测试在测试过程中对那些不容易构建的对象用一个虚拟对象来代替测试的方法就叫mock测试 4stub打桩就是为mock对象的方法指定返回值可抛出异常 5verify行为验证验证指定方法调用情况是否被调用调用次数等简单案例 Test public void test0() {//1、创建mock对象模拟依赖的对象final List mock Mockito.mock(List.class);//2、使用mock对象mock对象会对接口或类的方法给出默认实现System.out.println(mock.add result mock.add(first)); //falseSystem.out.println(mock.size result mock.size()); //0//3、打桩操作状态测试设置该对象指定方法被调用时的返回值Mockito.when(mock.get(0)).thenReturn(second);Mockito.doReturn(66).when(mock).size();//3、使用mock对象的stub测试打桩结果System.out.println(mock.get result mock.get(0)); //secondSystem.out.println(mock.size result mock.size()); //66//4、验证交互 verification行为测试验证方法调用情况Mockito.verify(mock).get(Mockito.anyInt());Mockito.verify(mock, Mockito.times(2)).size();//5、验证返回的结果这是JUnit的功能assertEquals(second, mock.get(0));assertEquals(66, mock.size()); } 1、行为验证 • 一旦mock对象被创建了mock对象会记住所有的交互然后你就可以选择性的验证你感兴趣的交互验证不通过则抛出异常。 Test public void test1() {final List mockList Mockito.mock(List.class);mockList.add(mock1);mockList.get(0);mockList.size();mockList.clear();// 验证方法被使用默认1次Mockito.verify(mockList).add(mock1);// 验证方法被使用1次Mockito.verify(mockList, Mockito.times(1)).get(0);// 验证方法至少被使用1次Mockito.verify(mockList, Mockito.atLeast(1)).size();// 验证方法没有被使用Mockito.verify(mockList, Mockito.never()).contains(mock2);// 验证方法至多被使用5次Mockito.verify(mockList, Mockito.atMost(5)).clear();// 指定方法调用超时时间Mockito.verify(mockList, timeout(100)).get(0);// 指定时间内需要完成的次数Mockito.verify(mockList, timeout(200).atLeastOnce()).size(); }2、如何做一些测试桩stub • 默认情况下所有的函数都有返回值。mock函数默认返回的是null一个空的集合或者一个被对象类型包装的内置类型例如0、false对应的对象类型为Integer、Boolean • 一旦测试桩函数被调用该函数将会一致返回固定的值 • 对于 static 和 final 方法 Mockito 无法对其 when(…).thenReturn(…) 操作。 Test public void test2() {//静态导入减少代码量import static org.mockito.Mockito.*;final ArrayList mockList mock(ArrayList.class);// 设置方法调用返回值when(mockList.add(test2)).thenReturn(true);doReturn(true).when(mockList).add(test2);System.out.println(mockList.add(test2)); //true// 设置方法调用抛出异常when(mockList.get(0)).thenThrow(new RuntimeException());doThrow(new RuntimeException()).when(mockList).get(0);System.out.println(mockList.get(0)); //throw RuntimeException// 无返回方法打桩doNothing().when(mockList).clear();// 为回调做测试桩对方法返回进行拦截处理final AnswerString answer new AnswerString() {Overridepublic String answer(InvocationOnMock invocationOnMock) throws Throwable {final List mock (List) invocationOnMock.getMock();return mock.size result mock.size();}};when(mockList.get(1)).thenAnswer(answer);doAnswer(answer).when(mockList).get(1);System.out.println(mockList.get(1)); //mock.size result 0// 对同一方法多次打桩以最后一次为准when(mockList.get(2)).thenReturn(test2_1);when(mockList.get(2)).thenReturn(test2_2);System.out.println(mockList.get(2)); //test2_2System.out.println(mockList.get(2)); //test2_2// 设置多次调用同类型结果when(mockList.get(3)).thenReturn(test2_1, test2_2);when(mockList.get(3)).thenReturn(test2_1).thenReturn(test2_2);System.out.println(mockList.get(3)); //test2_1System.out.println(mockList.get(3)); //test2_2// 为连续调用做测试桩为同一个函数调用的不同的返回值或异常做测试桩when(mockList.get(4)).thenReturn(test2).thenThrow(new RuntimeException());doReturn(test2).doThrow(new RuntimeException()).when(mockList).get(4);System.out.println(mockList.get(4)); //test2System.out.println(mockList.get(4)); //throw RuntimeException// 无打桩方法返回默认值System.out.println(mockList.get(99)); //null }3、参数匹配器 • 参数匹配器使验证和测试桩变得更灵活 • 为了合理的使用复杂的参数匹配使用equals()与anyX() 的匹配器会使得测试代码更简洁、简单。有时会迫使你重构代码以使用equals()匹配或者实现equals()函数来帮助你进行测试 • 如果你使用参数匹配器,所有参数都必须由匹配器提供 • 支持自定义参数匹配器 Test public void test3() {final Map mockMap mock(Map.class);// 正常打桩测试when(mockMap.get(key)).thenReturn(value1);System.out.println(mockMap.get(key)); //value1// 为灵活起见可使用参数匹配器when(mockMap.get(anyString())).thenReturn(value2);System.out.println(mockMap.get(anyString())); //value2System.out.println(mockMap.get(test_key)); //value2System.out.println(mockMap.get(0)); //null// 多个入参时要么都使用参数匹配器要么都不使用否则会异常when(mockMap.put(anyString(), anyInt())).thenReturn(value3);System.out.println(mockMap.put(key3, 3)); //value3System.out.println(mockMap.put(anyString(), anyInt())); //value3System.out.println(mockMap.put(key3, anyInt())); //异常// 行为验证时也支持使用参数匹配器verify(mockMap, atLeastOnce()).get(anyString());verify(mockMap).put(anyString(), eq(3));// 自定义参数匹配器final ArgumentMatcherArgumentTestRequest myArgumentMatcher new ArgumentMatcherArgumentTestRequest() {Overridepublic boolean matches(ArgumentTestRequest request) {return name.equals(request.getName()) || value.equals(request.getValue());}};// 自定义参数匹配器使用final ArgumentTestService mock mock(ArgumentTestService.class);when(mock.argumentTestMethod(argThat(myArgumentMatcher))).thenReturn(success);doReturn(success).when(mock).argumentTestMethod(argThat(myArgumentMatcher));System.out.println(mock.argumentTestMethod(new ArgumentTestRequest(name, value))); // successSystem.out.println(mock.argumentTestMethod(new ArgumentTestRequest())); //null }4、执行顺序验证 • 验证执行顺序是非常灵活的-你不需要一个一个的验证所有交互,只需要验证你感兴趣的对象即可 • 你可以仅通过那些需要验证顺序的mock对象来创建InOrder对象 Test public void test4() {// 验证同一个对象多个方法的执行顺序final List mockList mock(List.class);mockList.add(first);mockList.add(second);final InOrder inOrder inOrder(mockList);inOrder.verify(mockList).add(first);inOrder.verify(mockList).add(second);// 验证多个对象多个方法的执行顺序final List mockList1 mock(List.class);final List mockList2 mock(List.class);mockList1.get(0);mockList1.get(1);mockList2.get(0);mockList1.get(2);mockList2.get(1);final InOrder inOrder1 inOrder(mockList1, mockList2);inOrder1.verify(mockList1).get(0);inOrder1.verify(mockList1).get(2);inOrder1.verify(mockList2).get(1); }5、确保交互interaction操作不会执行在mock对象上 • 一些用户可能会在频繁地使用verifyNoMoreInteractions()甚至在每个测试函数中都用。但是verifyNoMoreInteractions()并不建议在每个测试函数中都使用 • verifyNoMoreInteractions()在交互测试套件中只是一个便利的验证它的作用是当你需要验证是否存在冗余调用时 Test public void test5() {// 验证某个交互是否从未被执行final List mock mock(List.class);mock.add(first);verify(mock, never()).add(test5); //通过verify(mock, never()).add(first); //异常// 验证mock对象没有交互过final List mock1 mock(List.class);final List mock2 mock(List.class);verifyZeroInteractions(mock1); //通过verifyNoMoreInteractions(mock1, mock2); //通过verifyZeroInteractions(mock, mock2); //异常// 注意可能只想验证前面的逻辑但是加上最后一行会导致出现异常。建议使用方法层面的验证如never()// 在验证是否有冗余调用的时候可使用此种方式。如下final List mockList mock(List.class);mockList.add(one);mockList.add(two);verify(mockList).add(one); // 通过verify(mockList, never()).get(0); //通过verifyZeroInteractions(mockList); //异常 }6、使用注解简化mock对象创建 注意下面这句代码需要在运行测试函数之前被调用,一般放到测试类的基类或者test runner中: MockitoAnnotations.initMocks(this);也可以使用内置的runner: MockitoJUnitRunner 或者一个rule : MockitoRule // 代替 mock(ArgumentTestService.class) 创建mock对象 Mock private ArgumentTestService argumentTestService; // 若改注解修饰的对象有成员变量Mock定义的mock对象会被自动注入 InjectMocks private MockitoAnnotationServiceImpl mockitoAnnotationServiceTest public void test6() {// 注意下面这句代码需要在运行测试函数之前被调用,一般放到测试类的基类或者test runner中;MockitoAnnotations.initMocks(this);when(argumentTestService.argumentTestMethod(new ArgumentTestRequest())).thenReturn(success);System.out.println(argumentTestService.argumentTestMethod(new ArgumentTestRequest())); //successSystem.out.println(mockitoAnnotationService.mockitoAnnotationTestMethod()); //null }7、监控真实对象部分mock • 可以为真实对象创建一个监控(spy)对象。当你使用这个spy对象时真实的对象也会也调用除非它的函数被stub了; • 尽量少使用spy对象使用时也需要小心形式例如spy对象可以用来处理遗留代码; • stub语法中同样提供了部分mock的方法可以调用真实的方法; 完全mock 上文讲的内容是完全mock即创建的mock对象与真实对象无关mock对象的方法默认都是基本的实现返回基本类型。可基于接口、实现类创建mock对象。 部分mock 所谓部分mock即创建的mock对象时基于真实对象的mock对象的方法都是默认使用真实对象的方法除非stub之后才会以stub为准。基于实现类创建mock对象否则在没有stub的情况下调用真实方法时会出现异常。 注意点 Mockito并不会为真实对象代理函数调用实际上它会拷贝真实对象。因此如果你保留了真实对象并且与之交互不要期望从监控对象得到正确的结果。 当你在监控对象上调用一个没有被stub的函数时并不会调用真实对象的对应函数你不会在真实对象上看到任何效果 Test public void test7() {// stub部分mockstub中使用真实调用。注意需要mock实现类否则会有异常final StubTestService stubTestService mock(StubTestServiceImpl.class);when(stubTestService.stubTestMethodA(paramA)).thenCallRealMethod();doCallRealMethod().when(stubTestService).stubTestMethodB();System.out.println(stubTestService.stubTestMethodA(paramA)); //stubTestMethodA is called, param paramASystem.out.println(stubTestService.stubTestMethodB()); //stubTestMethodB is calledSystem.out.println(stubTestService.stubTestMethodC()); //null// spy部分mockfinal LinkedListString linkedList new LinkedList();final LinkedList spy spy(linkedList);spy.add(one);spy.add(two);doReturn(100).when(spy).size();when(spy.get(0)).thenReturn(one_test);System.out.println(spy.size()); //100System.out.println(spy.get(0)); //one_testSystem.out.println(spy.get(1)); //two// spy可以类比AOP。在spy中由于默认是调用真实方法所以第二种写法不等价于第一种写法不推荐这种写法。doReturn(two_test).when(spy).get(2);when(spy.get(2)).thenReturn(two_test); //异常 java.lang.IndexOutOfBoundsException: Index: 2, Size: 2System.out.println(spy.get(2)); //two_test// spy对象只是真实对象的复制真实对象的改变不会影响spy对象final ListString arrayList new ArrayList();final ListString spy1 spy(arrayList);spy1.add(0, one);System.out.println(spy1.get(0)); //onearrayList.add(0, list1);System.out.println(arrayList.get(0)); //list1System.out.println(spy1.get(0)); //one// 若对某个方法stub之后又想调用真实的方法可以使用reset(spy)final ArrayListString arrayList1 new ArrayList();final ArrayListString spy2 spy(arrayList1);doReturn(100).when(spy2).size();System.out.println(spy2.size()); //100reset(spy2);System.out.println(spy2.size()); //0 }8、Mock 和 Spy的使用 • Mock 等价于 Mockito.mock(Object.class); • Spy 等价于 Mockito.spy(obj); 区分是mock对象还是spy对象 Mockito.mockingDetails(someObject).isMock(); Mockito.mockingDetails(someObject).isSpy();Mock private StubTestService stubTestService; Spy private StubTestServiceImpl stubTestServiceImpl; Spy private StubTestService stubTestServiceImpl1 new StubTestServiceImpl(); Test public void test8() {MockitoAnnotations.initMocks(this);// mock对象返回默认System.out.println(stubTestService.stubTestMethodB()); //null// spy对象调用真实方法System.out.println(stubTestServiceImpl.stubTestMethodC()); //stubTestMethodC is calledSystem.out.println(stubTestServiceImpl1.stubTestMethodA(spy)); //stubTestMethodA is called, param spy// 区分是mock对象还是spy对象System.out.println(mockingDetails(stubTestService).isMock()); //trueSystem.out.println(mockingDetails(stubTestService).isSpy()); //falseSystem.out.println(mockingDetails(stubTestServiceImpl).isSpy()); //true }9、ArgumentCaptor参数捕获器捕获方法参数进行验证。可代替参数匹配器使用 • 在某些场景中不光要对方法的返回值和调用进行验证同时需要验证一系列交互后所传入方法的参数。那么我们可以用参数捕获器来捕获传入方法的参数进行验证看它是否符合我们的要求。 ArgumentCaptor介绍 通过ArgumentCaptor对象的forClass(Class ArgumentCaptor的Api argument.capture() 捕获方法参数 argument.getValue() 获取方法参数值如果方法进行了多次调用它将返回最后一个参数值 argument.getAllValues() 方法进行多次调用后返回多个参数值 Test public void test9() {List mock mock(List.class);List mock1 mock(List.class);mock.add(John);mock1.add(Brian);mock1.add(Jim);// 获取方法参数ArgumentCaptor argument ArgumentCaptor.forClass(String.class);verify(mock).add(argument.capture());System.out.println(argument.getValue()); //John// 多次调用获取最后一次ArgumentCaptor argument1 ArgumentCaptor.forClass(String.class);verify(mock1, times(2)).add(argument1.capture());System.out.println(argument1.getValue()); //Jim// 获取所有调用参数System.out.println(argument1.getAllValues()); //[Brian, Jim] }10、简化 ArgumentCaptor 的创建 Mock private ListString captorList; Captor private ArgumentCaptorString argumentCaptor; Test public void test10() {MockitoAnnotations.initMocks(this);captorList.add(cap1);captorList.add(cap2);System.out.println(captorList.size());verify(captorList, atLeastOnce()).add(argumentCaptor.capture());System.out.println(argumentCaptor.getAllValues()); }11、高级特性自定义验证失败信息 Test public void test11() {final ArrayList arrayList mock(ArrayList.class);arrayList.add(one);arrayList.add(two);verify(arrayList, description(size()没有调用)).size();// org.mockito.exceptions.base.MockitoAssertionError: size()没有调用verify(arrayList, timeout(200).times(3).description(验证失败)).add(anyString());//org.mockito.exceptions.base.MockitoAssertionError: 验证失败 }12、高级特性修改没有测试桩的调用的默认返回值 • 可以指定策略来创建mock对象的返回值。这是一个高级特性通常来说你不需要写这样的测试 • 它对于遗留系统来说是很有用处的。当你不需要为函数调用打桩时你可以指定一个默认的answer Test public void test12(){// 创建mock对象、使用默认返回final ArrayList mockList mock(ArrayList.class);System.out.println(mockList.get(0)); //null// 这个实现首先尝试全局配置,如果没有全局配置就会使用默认的回答,它返回0,空集合,null,等等。// 参考返回配置ReturnsEmptyValuesmock(ArrayList.class, Answers.RETURNS_DEFAULTS);// ReturnsSmartNulls首先尝试返回普通值(0,空集合,空字符串,等等)然后它试图返回SmartNull。// 如果最终返回对象那么会简单返回null。一般用在处理遗留代码。// 参考返回配置ReturnsMoreEmptyValuesmock(ArrayList.class, Answers.RETURNS_SMART_NULLS);// 未stub的方法会调用真实方法。// 注1:存根部分模拟使用时(mock.getSomething ()) .thenReturn (fakeValue)语法将调用的方法。对于部分模拟推荐使用doReturn语法。// 注2:如果模拟是序列化反序列化,那么这个Answer将无法理解泛型的元数据。mock(ArrayList.class, Answers.CALLS_REAL_METHODS);// 深度stub用于嵌套对象的mock。参考https://www.cnblogs.com/Ming8006/p/6297333.htmlmock(ArrayList.class, Answers.RETURNS_DEEP_STUBS);// ReturnsMocks首先尝试返回普通值(0,空集合,空字符串,等等)然后它试图返回mock。// 如果返回类型不能mocked(例如是final)然后返回null。mock(ArrayList.class, Answers.RETURNS_MOCKS);// mock对象的方法调用后可以返回自己类似builder模式mock(ArrayList.class, Answers.RETURNS_SELF);// 自定义返回final AnswerString answer new AnswerString() {Overridepublic String answer(InvocationOnMock invocation) throws Throwable {return test_answer;}};final ArrayList mockList1 mock(ArrayList.class, answer);System.out.println(mockList1.get(0)); //test_answer }三、学习了这么多牛刀小试一下 测试实体类 Data public class User {/*** 姓名登录密码*/ 持久层DAO public interface UserDao {/*** 根据name查找user* param name* return*/User getUserByName(String name);/*** 保存user* param user* return*/Integer saveUser(User user); }业务层Service接口 public interface UserService {/*** 根据name查找user* param name* return*/User getUserByName(String name);/*** 保存user* param user* return*/Integer saveUser(User user); }业务层Serive实现类 Service public class UserServiceImpl implements UserService {//userDaoAutowiredprivate UserDao userDao;/*** 根据name查找user* param name* return*/Overridepublic User getUserByName(String name) {try {return userDao.getUserByName(name);} catch (Exception e) {throw new RuntimeException(查询user异常);}}/*** 保存user* param user* return*/Overridepublic Integer saveUser(User user) {if (userDao.getUserByName(user.getName()) ! null) {throw new RuntimeException(用户名已存在);}try {return userDao.saveUser(user);} catch (Exception e) {throw new RuntimeException(保存用户异常);}} }现在我们的Service写好了想要单元测试一下但是Dao是其他人开发的目前还没有写好那我们如何测试呢 public class UserServiceTest {/*** Mock测试根据name查询user*/Testpublic void getUserByNameTest() {// mock对象final UserDao userDao mock(UserDao.class);final UserServiceImpl userService new UserServiceImpl();userService.setUserDao(userDao);// stub调用final User user new User();user.setName(admin);user.setPassword(pass);when(userDao.getUserByName(admin)).thenReturn(user);// 执行待测试方法final User user1 userService.getUserByName(admin);System.out.println(查询结果 JacksonUtil.obj2json(user1)); //查询结果{name:admin,password:pass}// 验证mock对象交互verify(userDao).getUserByName(anyString());// 验证查询结果Assert.assertNotNull(查询结果为空, user1);Assert.assertEquals(查询结果错误, admin, user1.getName());}/*** Mock测试保存user*/Mockprivate UserDao userDao;InjectMocksprivate UserServiceImpl userService;Testpublic void saveUserTest() throws Exception{// 执行注解初始化MockitoAnnotations.initMocks(this);// mock对象stub操作final User user new User();user.setName(admin);user.setPassword(pass);when(userDao.getUserByName(admin)).thenReturn(user).thenReturn(null);when(userDao.saveUser(any(User.class))).thenReturn(1);// 验证用户名重复的情况try {userService.saveUser(user);throw new Exception(); //走到这里说明验证失败} catch (RuntimeException e) {System.out.println(重复用户名保存失败-测试通过); //重复用户名保存失败-测试通过}verify(userDao).getUserByName(admin);// 验证正常保存的情况user.setName(user);final Integer integer userService.saveUser(user);System.out.println(保存结果 integer); //保存结果1Assert.assertEquals(保存失败, 1, integer.longValue());verify(userDao).saveUser(any(User.class));verify(userDao, times(2)).getUserByName(anyString());}}根据以上代码我们可以知道当我们的待测类开发完成而依赖的类的实现还没有开发完成。此时我们就可以用到我们的Mock测试模拟我们依赖类的返回值使我们的待测类与依赖类解耦。这样我们就可以对我们的待测类进行单元测了。 四、参考文档及进一步学习 Mockito英文版javadochttps://javadoc.io/static/org.mockito/mockito-core/3.3.3/org/mockito/Mockito.html Mockito中文文档(部分)https://blog.csdn.net/bboyfeiyu/article/details/52127551#35Mockito使用教程https://www.cnblogs.com/Ming8006/p/6297333.html 参数捕获器使用https://www.journaldev.com/21892/mockito-argumentcaptor-captor-annotation 利用ArgumentCaptor参数捕获器捕获方法参数进行验证https://www.iteye.com/blog/hotdog-916364 改变mock返回值https://www.huangyunkun.com/2014/10/25/mockito-deep-stub-with-enum/ 五分钟了解Mockitohttps://www.iteye.com/blog/liuzhijun-1512780 使用Mockito进行单元测试https://www.iteye.com/blog/qiuguo0205-1443344 JUnit Mockito 单元测试https://blog.csdn.net/zhangxin09/article/details/42422643 Mockito中Mock与InjectMockhttps://www.cnblogs.com/langren1992/p/9681600.html mockito中两种部分mock的实现spy、callRealMethodhttps://www.cnblogs.com/softidea/p/4204389.html Mockito 中被 Mocked 的对象属性及方法的默认值https://www.cnblogs.com/fnlingnzb-learner/p/10635250.html 单元测试工具之Mockitohttps://blog.csdn.net/qq_32140971/article/details/90598454 引入Mockito测试用Spy和Mockhttps://blog.csdn.net/message_lx/article/details/83308114 Mockito初探(含实例)https://www.iteye.com/blog/sgq0085-2031319 测试覆盖率统计https://blog.csdn.net/lvyuan1234/article/details/82836052?depth_1-utm_sourcedistribute.pc_relevant.none-taskutm_sourcedistribute.pc_relevant.none-task 测试覆盖率无法统计解决https://blog.csdn.net/zhanglei082319/article/details/81536398Java-faker 单元测试构造数据非常费时费力多留意一些帮助测试的库能够极大提交效率。 Java的单元测试经常需要构造各种测试数据其中一项就是构造测试的字符串。 如果我们想要随机构造人名、地名、天气、学校、颜色、职业甚至符合某正则表达式的字符串等肿么办 那么有一个库叫 java-fake 可以实现这个功能。 maven中添加pom依赖 dependencygroupIdcom.github.javafaker/groupIdartifactIdjavafaker/artifactIdversion1.0.0/version /dependency基本用法 Faker faker new Faker();String name faker.name().fullName(); // Miss Samanta Schmidt String firstName faker.name().firstName(); // Emory String lastName faker.name().lastName(); // BartonString streetAddress faker.address().streetAddress(); // 60018 Sawayn Brooks Suite 449该框架支持多种语言默认是英文。 可以通过此代码指定语言 Faker faker new Faker(new Locale(“YOUR_LOCALE”)); 如果是中文zh-CN 支持正则 Testpublic void bothifyShouldGenerateLettersAndNumbers() {assertThat(faker.bothify(????##gmail.com), matchesRegularExpression(\\w{4}\\d{2}gmail.com));}Testpublic void letterifyShouldGenerateLetters() {assertThat(faker.bothify(????), matchesRegularExpression(\\w{4}));}Testpublic void letterifyShouldGenerateUpperCaseLetters() {assertThat(faker.bothify(????,true), matchesRegularExpression([A-Z]{4}));}Testpublic void letterifyShouldLeaveNonSpecialCharactersAlone() {assertThat(faker.bothify(ABC????DEF), matchesRegularExpression(ABC\\w{4}DEF));}此框架虽然可以构造各种字符串但是构造整个复杂对象或者集合就有些力不从心这时就需要另外一个强大的工具easy-random https://github.com/j-easy/easy-random easy-random 一两行就可以构造一个非常复杂的对象或者对象列表。 Java项目写单元测试时需要构造复杂对象非常耗时而且无用的代码很长非常不优雅。 这个工具主要是为了Mock对象省时省力结合Mockito可以mock方法堪称完美。 添加依赖 dependencygroupIdorg.jeasy/groupIdartifactIdeasy-random-core/artifactIdversion4.0.0/version /dependency正常情况要构造Person对象如果通过构造方法要这么写 Street street new Street(12, (byte) 1, Oxford street); Address address new Address(street, 123456, London, United Kingdom); Person person new Person(Foo, Bar, foo.bargmail.com, Gender.MALE, address);如果通过get set方法写 Street street new Street(); street.setNumber(12); street.setType((byte) 1); street.setName(Oxford street);Address address new Address(); address.setStreet(street); address.setZipCode(123456); address.setCity(London); address.setCountry(United Kingdom);Person person new Person(); person.setFirstName(Foo); person.setLastName(Bar); person.setEmail(foo.bargmail.com); person.setGender(Gender.MALE); person.setAddress(address);而使用easy-random只需要一行 public class Person {Overridepublic String toString() {return Person{ name name \ , email email \ };}private String name;private String email;public String getName() {return name;}public void setName(String name) {this.name name;}public String getEmail() {return email;}public void setEmail(String email) {this.email email;} } 我们的第一个示例生成一个简单的随机Person对象该对象没有嵌套对象集合只有一个Integer和两个String。 让我们使用nextObject(Class T t)生成对象的一个实例 Person person new EasyRandom().nextObject(Person.class)如我们所见生成的字符串可能有点太长并且年龄是负数。 我们将在后续部分中展示如何进行调整。 其他用法 可以产生一个int数组。 org.junit.Test public void testSortAlgorithm() {EasyRandom easyRandom new EasyRandom();// Givenint[] ints easyRandom.nextObject(int[].class);}可以生成一个Person对象插入到数据库中。 Test public void testPersistPerson() throws Exception {// GivenPerson person easyRandom.nextObject(Person.class);// WhenpersonDao.persist(person);// ThenassertThat(person_table).column(name).value().isEqualTo(person.getName()); // assretj db }对象集合 现在我们需要一个Person对象的集合。 另一个方法objects(Class T tint size)将允许我们这样做。 一件好事是它返回对象流因此最终我们可以根据需要向它或组添加中间操作。 这是我们如何生成Person的五个实例的方法 Test void givenDefaultConfiguration_thenGenerateObjectsList() {EasyRandom generator new EasyRandom();ListPerson persons generator.objects(Person.class, 5).collect(Collectors.toList());assertEquals(5, persons.size()); }复杂对象生成 让我们看一下Employee类 Data public class Employee {private long id;private String firstName;private String lastName;private Department department;private CollectionEmployee coworkers;private MapYearQuarter, Grade quarterGrades; }我们的类相对复杂它具有一个嵌套的对象一个集合和一个映射。 现在默认情况下集合的生成范围是1到100因此我们的Collection 大小将介于两者之间。 一件好事是对象将被缓存并重新使用因此不一定所有对象都是唯一的。 不过我们可能不需要那么多。 我们将很快研究如何调整集合的范围但是首先让我们看看我们可能遇到的另一个问题。 在我们的域中我们有一个YearQuarter类它代表一年的四分之一。 将endDate设置为精确指向开始日期后的3个月是有逻辑的 Data public class YearQuarter {private LocalDate startDate;private LocalDate endDate;public YearQuarter(LocalDate startDate) {this.startDate startDate;autoAdjustEndDate();}private void autoAdjustEndDate() {endDate startDate.plusMonths(3L);} }我们必须注意EasyRandom使用反射来构造我们的对象因此通过库生成该对象将导致数据很可能对我们没有用因为我们三个月的约束将无法保留。 让我们看看如何解决这个问题。 在以下配置中我们通过EasyRandomParameters提供我们的自定义配置。 首先我们明确说明所需的字符串长度和集合大小。 接下来我们从生成中排除了某些字段假设我们有一个仅包含null的原因。 在这里我们使用了方便的FieldPredicates实用程序来链接排除谓词。 之后我们通过另一个方便的TypePredicates实用程序将Java包中的所有内容从 not.existing.pkg中排除。 最后如所承诺的我们通过应用customYearQuarterRandomizer解决了有关YearQuarter类的startDate和endDate生成的问题 public class YearQuarterRandomizer implements RandomizerYearQuarter {Overridepublic YearQuarter getRandomValue() {return new YearQuarter(LocalDate.now());} }Testvoid givenCustomConfiguration_thenGenerateSingleEmployee() {EasyRandomParameters parameters new EasyRandomParameters();parameters.stringLengthRange(3, 3);parameters.collectionSizeRange(5, 5);parameters.excludeField(FieldPredicates.named(lastName).and(FieldPredicates.inClass(Employee.class)));parameters.excludeType(TypePredicates.inPackage(not.existing.pkg));parameters.randomize(YearQuarter.class, new YearQuarterRandomizer());EasyRandom generator new EasyRandom(parameters);Employee employee generator.nextObject(Employee.class);assertEquals(3, employee.getFirstName().length());assertEquals(5, employee.getCoworkers().size());assertEquals(5, employee.getQuarterGrades().size());assertNotNull(employee.getDepartment());assertNull(employee.getLastName());for (YearQuarter key : employee.getQuarterGrades().keySet()) {assertEquals(key.getStartDate(), key.getEndDate().minusMonths(3L));}} Postman Mock 1.Mock简介 1.1 Mock定义 Mock是一种比较特殊的测试技巧可以在没有依赖项的情况下进行接口或单元测试。通常情况下Mock与其他方法的区别是用于模拟代码依赖对象并允许设置对应的期望值。简单一点来讲就是Mock创建了一个对象模拟真实对象的行为。 1.2 Mock目的 因项目中任务的不同分工会出现每个人的任务进度不一样的情况。就会出现模块A开发完成但其依赖项模块B还未完成这时候如果进行集成测试时就会出现两个模块无法有效完成工作。针对这种情况Mock服务便应运而生。Postman中的Mock服务器可以减轻团队开发中这种不同步的情况。 1.3 Mock意义 在API开发的前期构建Mock集合可以帮助团队之间进行清晰有效沟通并尽快就预期结果达成一致。在实际开发过程中所有人员可以同步并行工作减少因相互依赖而导致延期的风险。 1.4 Mock服务 Mock不是一个真实的服务仅是一个被伪装成真实服务的假服务。通过Mock可以测试我们API并检验结果是否正确。 Postman可以创建两种类型的Mock服务 私有Mock 私有Mock服务需要在请求头中添加Postman API key如X-Api-Key:postman API key 公有Mock 公有Mocke服务可以被任何人访问在使用过程中不需要添加Postman API key 2. Postman 创建Mock服务 2.1 创建Mock服务 方法一通过菜单创建 方法二通过左侧任务栏创建 2.2 Postman创建Mock服务 2.2.1 Postman 创建Mock服务器参数 Request Method:请求方法 HTTP请求方法如GET、POST、PUT等 Request URL Mock服务器地址 Response Code: Mock服务器请求成功后返回的状态码 Response Body: Mock服务器返回的消息体 2.2.2 Postman创建Mock步骤 1.在左侧点击Mock Servers点击Create Mock Server在右侧填写相应的Mock服务器参数并点击Next如下所示 2.填写Mock服务器的相关信息并点击Create Mock Server如下所示 3.在创建Mock Server成功后会出现如下界面 3.访问Postman Mock服务 切换至Collections发送请求如下所示 GET请求Mock示例 POST请求Mock示例 TestNG TestNG是Java中的一个测试框架 类似于JUnit 和NUnit, 功能都差不多 只是功能更加强大使用也更方便。 Java中已经有一个JUnit的测试框架了TestNG比JUnit功能强大的多 测试人员一般用TestNG来写自动化测试开发人员一般用JUnit写单元测试。 官方网站: http://testng.org/doc/index.html 核心特点 TestNG 中的多线程使用姿势 使用场景 当测试回归用例集里包含了大量此类的用例时如果还用传统的单线程执行方式则一次自动化回归将会耗费大量的时间。 基于上述场景我们可以考虑将自动化用例中相互之间没有耦合关系相对独立的用例进行并行执行。如我可以通过起不同的线程同时去执行不同的 MR 任务、Spark 任务每个线程各自负责跟踪任务的执行情况。 此外即使是单纯的接口自动化测试如果测试集里包含了大量的用例时我们也可以借助于 TestNG 的多线程方式提高执行速度。 必须要指出的是通过多线程执行用例时虽然可以大大提升用例的执行效率但是我们在设计用例时也要考虑到这些用例是否适合并发执行以及要注意多线程方式的通病线程安全与共享变量的问题。建议是在测试代码中尽可能地避免使用共享变量。如果真的用到了要慎用 synchronized 关键字来对共享变量进行加锁同步。否则难免你的用例执行时可能会出现不稳定的情景经常听到有人提到用例执行地不稳定有时 100% 通过有时只有 90% 通过猜测可能有一部分原因也是这个导致的。 TestNG基本运用和运行 1、一个简单的例子如下 import org.testng.Assert; import org.testng.annotations.Test;public class Case {Testpublic void test(){System.out.println(this is testng case);Assert.assertTrue(true);} }直接用脚本方式运行右键Run xml方式运行新建testng.xml右键Run !DOCTYPE suite SYSTEM https://testng.org/testng-1.0.dtd suite nameSuite1 verbose1 test nameNopackage classesclass namecom.tech.suc.Case //classes/test /suiteTestNG注解说明 注解描述BeforeSuite在该套件的所有测试都运行在注释的方法之前仅运行一次AfterSuite在该套件的所有测试都运行在注释方法之后仅运行一次BeforeClass在调用当前类的第一个测试方法之前运行注释方法仅运行一次AfterClass在调用当前类的第一个测试方法之后运行注释方法仅运行一次BeforeTest注释的方法将在属于test标签内的类的所有测试方法运行之前运行AfterTest注释的方法将在属于test标签内的类的所有测试方法运行之后运行BeforeGroups配置方法将在之前运行组列表。 此方法保证在调用属于这些组中的任何一个的第一个测试方法之前不久运行AfterGroups此配置方法将在之后运行组列表。该方法保证在调用属于任何这些组的最后一个测试方法之后不久运行BeforeMethod注释方法将在每个测试方法之前运行AfterMethod注释方法将在每个测试方法之后运行DataProvider标记一种方法来提供测试方法的数据。 注释方法必须返回一个Object [] []其中每个Object []可以被分配给测试方法的参数列表。 要从该DataProvider接收数据的Test方法需要使用与此注释名称相等的dataProvider名称Factory将一个方法标记为工厂返回TestNG将被用作测试类的对象。 该方法必须返回Object []Listeners定义测试类上的侦听器Parameters描述如何将参数传递给Test方法Test将类或方法标记为测试的一部分此标记若放在类上则该类所有公共方法都将被作为测试方法 常用注解简单例子 import org.testng.annotations.Test;public class Case {Test(enabled false)public void Test1(){System.out.println(忽略测试此测试用例不会运行);}//“超时”表示如果单元测试花费的时间超过指定的毫秒数// 那么TestNG将会中止它并将其标记为失败。此项常用于性能测试Test(timeOut 5000)public void Test2(){System.out.println(超时测试);}Test(description Test3用例描述信息)public void Test3(){System.out.println(描述用于展示在测试报告中);}//依赖测试用例Test(dependsOnMethods {Test2})public void Test4(){System.out.println(依赖测试执行该用例前会先执行Test1用例);}//依赖测试用例分组Test(dependsOnGroups {group1})public void Test5(){System.out.println(依赖测试执行该用例前会先执行Test1用例);}Test(groups group1)public void Test6(){System.out.println(分组测试1Test6);}Test(groups group1)public void Test7(){System.out.println(分组测试1Test7);}Test(groups group2)public void Test8(){System.out.println(分组测试group2在xml执行时可以体现);} }其他说明 依赖测试 TestNG允许指定依赖关系 在Test注释中使用属性dependsOnMethods在Test注释中使用属性dependsOnGroups 除此之外依赖还分为hard依赖和soft依赖 hard依赖 默认为此依赖方式 即其所有依赖的methods或者groups必须全部pass 否则被标识依赖的类或者方法将会被略过在报告中标识为skip如后面的范例所示此为默认的依赖方式 以下实例的被依赖方法Test4的结果为fail因为所依赖的methodTest1不执行即fail所以会导致被依赖Test4fail。若Test1是true则Test4执行成功。 import org.testng.annotations.Test;public class Case {Test(enabled false)public void Test1(){System.out.println(忽略测试此测试用例不会运行);}//依赖测试用例Test(dependsOnMethods {Test1})public void Test4(){System.out.println(依赖测试执行该用例前会先执行Test1用例);} }**soft依赖**此方式下其依赖的方法或者组有不是全部pass也不会影响被标识依赖的类或者方法的运行注意如果使用此方式则依赖者和被依赖者之间必须不存在成功失败的因果关系否则会导致用例失败。此方法在注解中需要加入alwaysRuntrue即可如Test(dependsOnMethods {“TestNgLearn1”} alwaysRuntrue) XML中的并发 测试代码TestMethods.java import org.testng.Assert; import org.testng.Reporter; import org.testng.annotations.Test;public class TestMethods {Testpublic void test1(){Assert.assertEquals(2,2);System.out.println(this is thread Thread.currentThread().getId());}Testpublic void test2(){Assert.assertEquals(1,1);System.out.println(this is thread Thread.currentThread().getId());}Testpublic void test3(){Assert.assertEquals(sss,sss);System.out.println(this is thread Thread.currentThread().getId());}}xml设置tests级别并发示例 testng.xml ?xml version1.0 encodingUTF-8 ?suite nameSuite1 paralleltests thread-count2test name测试用例1classesclass namecom.test.extent.TestMethods/class/classes/testtest name测试用例2classesclass namecom.test.extent.TestMethods/class/classes/testtest name测试用例3classesclass namecom.test.extent.TestMethods/class/classes/test /suite说明在当前测试规划的执行过程中为每个测试用例指的是xml中的的执行使用单独的线程该测试用例中的测试方法共享一个线程 最多并发2个线程执行结果如下图的3个方法的线程id均为12 xml设置classes级别并发示例 ?xml version1.0 encodingUTF-8 ?suite nameSuite1 parallelclasses thread-count2test name测试用例1classesclass namecom.test.extent.TestMethods/classclass namecom.test.extent.TestMethods2/class/classes/test /suite说明在当前测试规划的执行过程中为每个测试类指的是xml中的的执行使用单独的线程该测试类中的测试方法共享一个线程最多并发2个线程。执行结果如下图 xml设置methods级别并发示例 ?xml version1.0 encodingUTF-8 ?suite nameSuite1 parallelmethods thread-count2test nametest1classesclass namecom.test.extent.TestMethods/class/classes/test /suite说明在当前测试规划的执行过程中为每个测试方法指的是每个Test的执行使用单独的线程最多并发2个线程执行结果如下图 不同级别的并发测试 通常在 TestNG 的执行中测试的级别由上至下可以分为suite - test - class - method箭头的左边元素跟右边元素的关系是一对多的包含关系。 这里的 test 指的是 testng.xml 中的 test tag而不是测试类里的一个**Test。测试类里的一个**Test实际上对应这里的 method。所以我们在使用**BeforeSuite、**BeforeTest、**BeforeClass、**BeforeMethod这些标签的时候它们的实际执行顺序也是按照这个级别来的。 suite 一般情况下一个 testng.xml 只包含一个 suite。如果想起多个线程执行不同的 suite官方给出的方法是通过命令行的方式来指定线程池的容量。 java org.testng.TestNG -suitethreadpoolsize 3 testng1.xml testng2.xml testng3.xml即可通过三个线程来分别执行 testng1.xml、testng2.xml、testng3.xml。 实际上这种情况在实际中应用地并不多见我们的测试用例往往放在一个 suite 中如果真需要执行不同的 suite往往也是在不同的环境中去执行届时也自然而然会做一些其他的配置如环境变量更改会有不同的进程去执行。因此这种方式不多赘述。 test, class, method testclassmethod 级别的并发可以通过在 testng.xml 中的 suite tag 下设置如 suite nameTestng Parallel Test paralleltests thread-count5 suite nameTestng Parallel Test parallelclasses thread-count5 suite nameTestng Parallel Test parallelmethods thread-count5它们的共同点都是最多起 5 个线程去同时执行不同的用例。 它们的区别如下 tests 级别不同 test tag 下的用例可以在不同的线程执行相同 test tag 下的用例只能在同一个线程中执行。classs 级别不同 class tag 下的用例可以在不同的线程执行相同 class tag 下的用例只能在同一个线程中执行。methods 级别所有用例都可以在不同的线程去执行。 搞清楚并发的级别非常重要可以帮我们合理地组织用例比如将非线程安全的测试类或 group 统一放到一个 test 中这样在并发的同时又可以保证这些类里的用例是单线程执行。也可以根据需要设定 class 级别的并发让同一个测试类里的用例在同一个线程中执行。 并发时的依赖 实践中很多时候我们在测试类中通过 dependOnMethods/dependOnGroups 方式给很多测试方法的执行添加了依赖以达到期望的执行顺序。如果同时在运行 testng 时配置了 methods 级别并发执行那么这些测试方法在不同线程中执行还会遵循依赖的执行顺序吗答案是——YES。牛逼的 TestNG 就是能在多线程情况下依然遵循既定的用例执行顺序去执行。 不同 dataprovider 的并发 在使用 TestNG 做自动化测试时基本上大家都会使用 dataprovider 来管理一个用例的不同测试数据。而上述在 testng.xml 中修改 suite 标签的方法并不适用于 dataprovider 多组测试数据之间的并发。执行时会发现一个 dp 中的多组数据依然是顺序执行。 解决方式是在**DataProvider中添加 paralleltrue。 如 import org.testng.annotations.DataProvider; import testdata.ScenarioTestData;public class ScenarioDataProvider {DataProvider(name hadoopTest, paralleltrue)public static Object [][] hadoopTest(){return new Object[][]{ScenarioTestData.hadoopMain,ScenarioTestData.hadoopRun,ScenarioTestData.hadoopDeliverProps};}DataProvider(name sparkTest, paralleltrue)public static Object [][] sparkTest(){return new Object[][]{ScenarioTestData.spark_java_version_default,ScenarioTestData.spark_java_version_162,ScenarioTestData.spark_java_version_200,ScenarioTestData.spark_python};}DataProvider(name sqoopTest, paralleltrue)public static Object [][] sqoopTest(){return new Object[][]{ScenarioTestData.sqoop_mysql2hive,ScenarioTestData.sqoop_mysql2hdfs};} }默认情况下dp 并行执行的线程池容量为 10如果要更改并发的数量也可以在 suite tag 下指定参数 data-provider-thread-count suite nameTestng Parallel Test parallelmethods thread-count5 data-provider-thread-count20 同一个方法的并发 有些时候我们需要对一个测试用例比如一个 http 接口执行并发测试即一个接口的反复调用。TestNG 中也提供了优雅的支持方式在**Test标签中指定 threadPoolSize 和 invocationCount。 Test(enabledtrue, dataProvidertestdp, threadPoolSize5, invocationCount10)其中 threadPoolSize 表明用于调用该方法的线程池容量该例就是同时起 5 个线程并行执行该方法invocationCount 表示该方法总计需要被执行的次数。该例子中 5 个线程同时执行当总计执行次数达到 10 次时停止。 注意该线程池与 dp 的并发线程池是两个独立的线程池。这里的线程池是用于起多个 method而每个 method 的测试数据由 dp 提供如果这边 dp 里有 3 组数据那么实际上 10 次执行每次都会调 3 次接口这个接口被调用的总次数是 10*330 次。threadPoolSize 指定的 5 个线程中每个线程单独去调 method 时用到的 dp 如果也是支持并发执行的话会创建一个新的线程池dpThreadPool来并发执行测试数据。 示例代码如下 package testng.parallel.test;import java.text.SimpleDateFormat; import java.util.Date;import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test;public class TestClass1 {private SimpleDateFormat df new SimpleDateFormat(yyyy-MM-dd HH:mm:ss);//设置日期格式BeforeClasspublic void beforeClass(){System.out.println(Start Time: df.format(new Date()));}Test(enabledtrue, dataProvidertestdp, threadPoolSize2, invocationCount5)public void test(String dpNumber) throws InterruptedException{System.out.println(Current Thread Id: Thread.currentThread().getId() . Dataprovider number: dpNumber);Thread.sleep(5000);}DataProvider(name testdp, parallel true)public static Object[][]testdp(){return new Object[][]{{1},{2}};}AfterClasspublic void afterClass(){System.out.println(End Time: df.format(new Date()));} }测试结果 Start Time: 2017-03-11 14:10:43 [ThreadUtil] Starting executor timeOut:0ms workers:5 threadPoolSize:2 Current Thread Id: 14. Dataprovider number: 2 Current Thread Id: 15. Dataprovider number: 2 Current Thread Id: 12. Dataprovider number: 1 Current Thread Id: 13. Dataprovider number: 1 Current Thread Id: 16. Dataprovider number: 1 Current Thread Id: 18. Dataprovider number: 1 Current Thread Id: 17. Dataprovider number: 2 Current Thread Id: 19. Dataprovider number: 2 Current Thread Id: 21. Dataprovider number: 2 Current Thread Id: 20. Dataprovider number: 1 End Time: 2017-03-11 14:10:58参数化测试 在自动化测试项目中参数化是必不可少的以下将会介绍TestNG中的参数化测试运用。 TestNG可以通过两种不同的方式将参数直接传递给测试方法 使用testng.xml使用数据提供者 使用testng.xml传送参数 import org.testng.annotations.Parameters; import org.testng.annotations.Test;public class Case {TestParameters({username,password})public void Login(String username, String password){System.out.println(您的用户名是username);System.out.println(您的密码是password);} }xml配置如下 !DOCTYPE suite SYSTEM https://testng.org/testng-1.0.dtd suite nameSuite1 verbose1 test nameparamparameter nameusername value李白/parameterparameter namepassword value123456/parameterclassesclass namecom.tech.design.Case/class/classes/test /suite运行xml结果如下 使用DataProvider传递参数 如果需要传递复杂的参数或java创建的对象(复杂对象、从属性文件或数据库读取数据等)通过testng.xml文件的方式可能不太适合。这种情况可以使用数据驱动的方式为你的测试提供数据。数据库驱动是在类中定义一个方法返回一组数据对象。该方法使用DataProvider注解。 此处需要注意传参的类型必须要一致且带有DataProvider注解的函数返回的必然是Object[][]此处需要注意。 通过DataProvider返回值分别是Object[][]和IteratorObject[] 1、返回值是Object[][]代码如下 import org.testng.annotations.DataProvider; import org.testng.annotations.Parameters; import org.testng.annotations.Test;public class Case {DataProvider(name data)public Object[][] provideData(){return new Object[][] { {李白,100},{杜甫,110},{鲁班,210} };}//若调用者和提供在不同的类则写法如下  //Test(dataProvider data,dataProviderClass Case.class)Test(dataProvider data)public void Test(String par1, int par2){System.out.println(姓名par1,年龄par2);}}2、返回值是IteratorObject[]代码如下 import org.testng.annotations.DataProvider; import org.testng.annotations.Parameters; import org.testng.annotations.Test;import java.util.HashSet; import java.util.Iterator;public class Case {DataProvider(nametestdp)public static IteratorObject[] createData() {HashSetInteger set new HashSetInteger();set.add(Integer.valueOf(4));set.add(Integer.valueOf(5));HashSetObject[] so new HashSetObject[]();for(Integer intg:set){so.add(new Object[]{intg});}return so.iterator();}Test(dataProvidertestdp)public void login(Integer caseNum) {System.out.println(caseNum);}}3、dataProvider方法可接受 的参数Method method, ITestContext context 参数可以传其中一个也可以两个一起传入这里只演示Method参数 用处当多个测试方法使用同一个DataProvider提供的测试数据并希望不同的测试方法返回不同的值时这是很有用的方式 示例定义1个数据提供方法和2个测试方法。 import org.testng.annotations.DataProvider; import org.testng.annotations.Test;import java.lang.reflect.Method; public class Case {DataProvider(name datapro)public Object[][] Data(Method method){System.out.println(当前测试方法为method.getName());Object[] S1 new Object[]{李白};Object[] S2 new Object[]{张楚};if(method.getName().equals(Test2)){return new Object[][] {S1};}else {return new Object[][] {S2};}}Test(dataProvider datapro)public void Test1(String s){System.out.println(s);}Test(dataProvider datapro)public void Test2(String s){System.out.println(s);}}Allure测试报告 Allure框架是一个灵活轻量级多语言测试报告工具它不仅可以以WEB的方式展示简介的测试结果而且允许参与开发过程的每个人从日常执行的测试中最大限度的提取有用信息。     Allure报告简化了常见缺陷的统计失败的测试可以分为BUG和被中断的测试还可以配置日志、步骤、fixture、附件、计时、执行历史以及与BUG管理系统集成所以通过以上配置所有负责的开发人员和测试人员可以尽可能的掌握测试信息。 Allure安装 本次用maven项目演示直接用pom自动更新下载依赖包allure具体代码如下 Windows安装allure工具 1、安装jdk配置环境变量 2、下载allure安装包并配置环境变量 .下载Allure命令行下载地址如下所示 https://github.com/allure-framework/allure2/releases/将下载到本地的allure压缩包解压到指定目录并添加相应的环境变量 PathD:\Program Files\Allure\allure-2.16.0\bin在命令行中输入allure不出现报错即可 Usage: allure [options] [command] [command options]Options:--helpPrint commandline help.-q, --quietSwitch on the quiet mode.Default: false...allure执行 1、用pom.xml拉好依赖包后执行测试用例 2、测试用例执行完成后会在项目目录下生成allure-results文件夹 3、最后通过IDEA 的Terminal功能在当前项目下执行如下命令 allure generate allure-results #生成一个指定的报告到指定位置 (默认生成allure-report文件)allure generate allure-results -o allure-report --clean #清空已有测试报告后再生成allure open allure-report #打开生成的报告 maven项目为例说如何使用 添加pom依赖与allure插件 ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.7.9/versionrelativePath/ !-- lookup parent from repository --/parentgroupIdcom.example/groupIdartifactIddemo/artifactIdversion0.0.1-SNAPSHOT/versionnamedemo/namedescriptionDemo project for Spring Boot/descriptionpropertiesjava.version1.8/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependencydependencygroupIdorg.testng/groupIdartifactIdtestng/artifactIdversion6.14.3/version/dependency!-- 依赖reportNg 关联testNg--dependencygroupIdorg.uncommons/groupIdartifactIdreportng/artifactIdversion1.1.4/versionscopetest/scopeexclusionsexclusiongroupIdorg.testng/groupIdartifactIdtestng/artifactId/exclusion/exclusions/dependency!--allure的testng插件--dependencygroupIdru.yandex.qatools.allure/groupIdartifactIdallure-testng-adaptor/artifactIdversion1.3.6/versionexclusionsexclusiongroupIdorg.testng/groupIdartifactIdtestng/artifactId/exclusion/exclusions/dependencydependencygroupIdio.qameta.allure/groupIdartifactIdallure-testng/artifactIdversion2.17.0/version/dependency!-- 依赖Guice --dependencygroupIdcom.google.inject/groupIdartifactIdguice/artifactIdversion4.0/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-test/artifactId/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdconfigurationexcludesexcludegroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/exclude/excludes/configuration/pluginplugingroupIdorg.apache.maven.plugins/groupIdartifactIdmaven-surefire-plugin/artifactIdversion2.20/versionconfigurationargLine-javaagent:${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar/argLine!--生成allure-result的目录--systemPropertiespropertynameallure.results.directory/namevalue./target/allure-results/value/property/systemProperties/configurationdependenciesdependencygroupIdorg.aspectj/groupIdartifactIdaspectjweaver/artifactIdversion${aspectj.version}/version/dependency/dependencies/plugin/plugins/build/project 重新生成使用 allure generate allure-results -o allure-report --clean 执行 allure open allure-report 打开 查看测试报告。 Other TestNG Tips TestNG 作为一个成熟的、业界广泛使用的测试框架自然有其存在的合理性。这边再分享一些简单有用的标签具体的使用姿势大家可以自己去探索官网有比较全的介绍毕竟自己探索的才会印象深刻。 groups/dependsOnGroups/dependsOnMethods ——设置用例间依赖dataProviderClass ——将 dataprovider 单独放到一个专用的类中实现测试代码、dataprovider、测试数据分层。timeout ——设置用例的超时时间并发非并发都可支持alwaysRun ——某些依赖的用例失败了导致用例被跳过。对于一些为了保持环境干净而 “扫尾” 的测试类如果我们想强制执行可以使用此标签。priority ——设置优先级让某些测试用例被更大概率优先执行。singleThreaded ——强制一个 class 类里的用例在一个线程执行忽视 method 级别并发preserve-order ——指定是否按照 testng.xml 中的既定用例顺序执行用例 总结 在 TestNG 中使用多线程的方式并行执行测试用例可以有效提供用例的执行速度而且 TestNG 对多线程提供了很好的支持即使是菜鸟也可以方便地上手多线程。此外TestNG 默认会使用线程池的方式创建线程减小了程序的开销。
http://www.tj-hxxt.cn/news/131589.html

相关文章:

  • 如何用源代码做网站wordpress后台分类添加图片
  • 建设银行信用卡官网站房地产开发公司招聘岗位
  • 贵州微网站建设公司园林景观设计公司抖音推广
  • 深圳做营销型网站营销引流都有什么方法
  • 学校学院网站建设目标如何找人帮我做网站推广
  • 如何做网站的线下推广网站热销榜怎么做
  • c h5网站开发wordpress 导入html
  • 温州网站建设及推广wordpress富文本编辑器
  • 网站建设计划图东莞做网站制作
  • 建企业网站找个网站怎么这么难
  • 3d建模网站邯郸网络作家村
  • 宜昌网站设计秦皇岛乾兴建设招聘
  • 怎样做好网站用户体验动效做的好的网站
  • wordpress子站点用户无角色北京果木烤鸭制作方法
  • 大型门户网站开发公司有app怎么做网站
  • 网站后台上传文件网站开发的交付文档
  • 菏泽做网站推广开源网站程序
  • 网站源代码安装网络工程师简历
  • 做课程的网站沙田镇网站建设公司
  • 广东省住房建设厅网站行唐县做网站电话
  • 公司想做个网站怎么办宁波广告公司
  • 南宁怎么做网站做网站用dw的多吗
  • 天津餐饮团购网站建设淘宝网官网登录首页
  • 赣州市住房和城乡建设局网站怀宁网站建设
  • 一个网站一级栏目专做餐饮的网站
  • 中山市网站建设 中企动力html静态网站开发实验
  • 建设银行网上银行网站永久免费自助建站
  • 塘沽网站制作公司怎么自学网站建设
  • 网站规划可以分成哪几步上海网站建设系统
  • 平面设计公司网站2017山亭区建设局网站