单元测试总结

原创 2018年04月17日 10:25:38

1.软件测试

软件测试是一种用来鉴定软件的正确性、完整性、安全性和质量的过程。主要包括单元测试、集成测试和功能测试等。

1.1 单元测试

主要由开发人员进行,确保程序单元符合预期。

1.2 集成测试

主要由开发人员进行,测试整体程序等功能和性能。

1.3 功能测试

主要由测试人员进行,测试程序是否符合预期。

2.单元测试内容

  1. 模块接口测试
  2. 模块局部数据结构测试
  3. 模块边界条件测试
  4. 模块中所有独立执行通路测试
  5. 模块的各条错误处理通路测试
  6. 模块的非法输入测试
  7. 代码重用测试
  8. 系统兼容测试

3.单元测试最佳实践

3.1 三到五步(Setup,输入,调用,输出,TearDown)

3.2 一致性(任何时候同样的输入需要同样的结果)

反例:

Date date = new Date();
Random.next();

3.3 原子性

所有的测试只有两种结果(成功或失败,不能部分测试通过)

3.4 单一职责

一个测试只验证一个行为

3.5 独立无耦合

  • 单元测试之间无相互调用(单元测试执行顺序无关)
  • 单元测试之间不能共享

3.6 隔离外部调用(不使用不依赖具体、真实的数据,例如:数据库、网络、外部文件等)

3.7 自描述(开发级文档)

3.8 单元测试逻辑

3.9 断言(包含具体的错误信息)

4.Mockito

单元测试开发中,我们经常会遇到测试的类有很多依赖的类、对象、资源,从而形成巨大的依赖树,mock可以模拟外部依赖,适应单元测试。

5.Mockito示例

模拟对象

// 模拟LinkedList 的一个对象  
LinkedList mockedList = mock(LinkedList.class);
// 此时调用get方法,会返回null,因为还没有对方法调用的返回值做模拟
System.out.println(mockedList.get(0)); 

模拟方法调用的返回值

// 模拟获取第一个元素时,返回字符串first。  给特定的方法调用返回固定值在官方说法中称为stub。
when(mockedList.get(0)).thenReturn("first");
// 此时打印输出first
System.out.println(mockedList.get(0)); 

模拟方法调用抛出异常

// 模拟获取第二个元素时,抛出RuntimeException  
when(mockedList.get(1)).thenThrow(new RuntimeException());
// 此时将会抛出RuntimeException  
System.out.println(mockedList.get(1));

如果一个函数没有返回值类型,那么可以使用此方法模拟异常抛出

doThrow(new RuntimeException("clear exception")).when(mockedList).clear();
mockedList.clear();

模拟调用方法时的参数匹配

// anyInt()匹配任何int参数,这意味着参数为任意值,其返回值均是element  
when(mockedList.get(anyInt())).thenReturn("element");
// 此时打印是element
System.out.println(mockedList.get(999));

模拟方法调用次数

// 调用add一次
mockedList.add("once"); 
// 下面两个写法验证效果一样,均验证add方法是否被调用了一次
verify(mockedList).add("once");
verify(mockedList, times(1)).add("once"); 

校验行为

// mock creation
 List mockedList = mock(List.class);
 // using mock object
 mockedList.add("one");
 mockedList.clear();
 //verification
 verify(mockedList).add("one");
 verify(mockedList).clear();

模拟方法调用(Stubbing)

//You can mock concrete classes, not just interfaces
 LinkedList mockedList = mock(LinkedList.class);
 //stubbing
 when(mockedList.get(0)).thenReturn("first");
 when(mockedList.get(1)).thenThrow(new RuntimeException());
 //following prints "first"
 System.out.println(mockedList.get(0));
 //following throws runtime exception
 System.out.println(mockedList.get(1));
 //following prints "null" because get(999) was not stubbed
 System.out.println(mockedList.get(999));
 verify(mockedList).get(0);

参数匹配

//stubbing using built-in anyInt() argument matcher
 when(mockedList.get(anyInt())).thenReturn("element");
 //stubbing using custom matcher (let's say isValid() returns your own matcher implementation):
 when(mockedList.contains(argThat(isValid()))).thenReturn("element");
 //following prints "element"
 System.out.println(mockedList.get(999));
 //you can also verify using an argument matcher
 verify(mockedList).get(anyInt());
 //argument matchers can also be written as Java 8 Lambdas
 verify(mockedList).add(someString -> someString.length() > 5);

校验方法调用次数

//using mock
 mockedList.add("once");

 mockedList.add("twice");
 mockedList.add("twice");

 mockedList.add("three times");
 mockedList.add("three times");
 mockedList.add("three times");
 //following two verifications work exactly the same - times(1) is used by default
 verify(mockedList).add("once");
 verify(mockedList, times(1)).add("once");
 //exact number of invocations verification
 verify(mockedList, times(2)).add("twice");
 verify(mockedList, times(3)).add("three times");
 //verification using never(). never() is an alias to times(0)
 verify(mockedList, never()).add("never happened");
 //verification using atLeast()/atMost()
 verify(mockedList, atLeastOnce()).add("three times");
 verify(mockedList, atLeast(2)).add("five times");
 verify(mockedList, atMost(5)).add("three times");

模拟无返回方法抛出异常

doThrow(new RuntimeException()).when(mockedList).clear();
//following throws RuntimeException:
mockedList.clear();

校验方法调用顺序

// A. Single mock whose methods must be invoked in a particular order
 List singleMock = mock(List.class);
 //using a single mock
 singleMock.add("was added first");
 singleMock.add("was added second");
 //create an inOrder verifier for a single mock
 InOrder inOrder = inOrder(singleMock);
 //following will make sure that add is first called with "was added first, then with "was added second"
 inOrder.verify(singleMock).add("was added first");
 inOrder.verify(singleMock).add("was added second");
// B. Multiple mocks that must be used in a particular order
 List firstMock = mock(List.class);
 List secondMock = mock(List.class);
 //using mocks
 firstMock.add("was called first");
 secondMock.add("was called second");
 //create inOrder object passing any mocks that need to be verified in order
 InOrder inOrder = inOrder(firstMock, secondMock);
 //following will make sure that firstMock was called before secondMock
 inOrder.verify(firstMock).add("was called first");
 inOrder.verify(secondMock).add("was called second");
 // Oh, and A + B can be mixed together at will

校验方法是否从未调用

//using mocks - only mockOne is interacted
 mockOne.add("one");
 //ordinary verification
 verify(mockOne).add("one");
 //verify that method was never called on a mock
 verify(mockOne, never()).add("two");
 //verify that other mocks were not interacted
 verifyZeroInteractions(mockTwo, mockThree);

快速创建Mock对象

public class ArticleManagerTest {
   @Mock private ArticleCalculator calculator;
      @Mock private ArticleDatabase database;
      @Mock private UserProvider userProvider;
      @Before
      public void before(){
          MockitoAnnotations.initMocks(this);
      }
}

自定义返回不同结果

when(mock.someMethod("some arg"))
   .thenThrow(new RuntimeException())  // 第一次会抛出异常
   .thenReturn("foo"); // 第二次会返回这个结果
//First call: throws runtime exception:
mock.someMethod("some arg"); // 第一次
//Second call: prints "foo"
System.out.println(mock.someMethod("some arg")); // 第二次
//Any consecutive call: prints "foo" as well (last stubbing wins).
System.out.println(mock.someMethod("some arg")); // 第n次(n> 2),依旧以最后返回最后一个配置

对返回结果进行拦截

when(mock.someMethod(anyString())).thenAnswer(new Answer() {
    Object answer(InvocationOnMock invocation) {
        Object[] args = invocation.getArguments();
        Object mock = invocation.getMock();
        return "called with arguments: " + args;
    }
});
//the following prints "called with arguments: foo"
System.out.println(mock.someMethod("foo"));

Mock函数操作

可以通过doThrow(), doAnswer(), doNothing(), doReturn() and doCallRealMethod() 来自定义函数操作。
暗中调用真实对象

List list = new LinkedList();
List spy = spy(list);
//optionally, you can stub out some methods:
when(spy.size()).thenReturn(100);
//using the spy calls *real* methods
spy.add("one");
spy.add("two");
//prints "one" - the first element of a list
System.out.println(spy.get(0));
//size() method was stubbed - 100 is printed
System.out.println(spy.size());
//optionally, you can verify
verify(spy).add("one");
verify(spy).add("two");

改变默认返回值

Foo mock = mock(Foo.class, Mockito.RETURNS_SMART_NULLS);
Foo mockTwo = mock(Foo.class, new YourOwnAnswer());

捕获函数的参数值

ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
verify(mock).doSomething(argument.capture());
assertEquals("John", argument.getValue().getName());

部分Mock

//you can create partial mock with spy() method:
List list = spy(new LinkedList());
//you can enable partial mock capabilities selectively on mocks:
Foo mock = mock(Foo.class);
//Be sure the real implementation is 'safe'.
//If real implementation throws exceptions or depends on specific state of the object then you're in trouble.
when(mock.someMethod()).thenCallRealMethod();

重置Mock

List mock = mock(List.class);
when(mock.size()).thenReturn(10);
mock.add(1);
reset(mock);
//at this point the mock forgot any interactions & stubbing

序列化

List<Object> list = new ArrayList<Object>();
List<Object> spy = mock(ArrayList.class, withSettings()
                 .spiedInstance(list)
                 .defaultAnswer(CALLS_REAL_METHODS)
                 .serializable());

检查超时

//passes when someMethod() is called within given time span
verify(mock, timeout(100)).someMethod();
//above is an alias to:
verify(mock, timeout(100).times(1)).someMethod();
//passes when som`eMethod() is called *exactly* 2 times within given time span
verify(mock, timeout(100).times(2)).someMethod();
//passes when someMethod() is called *at least* 2 times within given time span
verify(mock, timeout(100).atLeast(2)).someMethod();
//verifies someMethod() within given time span using given verification mode
//useful only if you have your own custom verification modes.
verify(mock, new Timeout(100, yourOwnVerificationMode)).someMethod();

Mock详情

Mockito.mockingDetails(someObject).isMock();
Mockito.mockingDetails(someObject).isSpy();
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sunbufu/article/details/79971000

【软考】白盒测试总结

测试是软件开发不可少的步骤、从单元测试到最后的集成测试、一步不能少、可以说没有测试过的软件是不能上线的、测试最耳熟能详的就是黑盒白盒测试了、今天就说下白盒测试 白盒测试   语句覆盖:执行每一条语句、...
  • u010191034
  • u010191034
  • 2015-05-19 10:46:49
  • 809

Android 单元测试(三)总结

Android 单元测试
  • u010218288
  • u010218288
  • 2015-08-25 11:04:22
  • 445

Java单元测试小白总结

本文绝大部分内容引自这篇文章: http://www.devx.com/Java/Art...
  • wfk2975019671
  • wfk2975019671
  • 2018-03-23 13:27:17
  • 9

java单元测试总结

java单元测试(使用junit) http://www.cnblogs.com/feiweiwei/archive/2009/06/16/1024623.html     JUnit是由 Eri...
  • bcbobo21cn
  • bcbobo21cn
  • 2017-03-12 17:49:56
  • 185

单元测试报告模板

  • 2015年04月27日 13:34
  • 56KB
  • 下载

VS2015中使用单元测试的方法-以fibonacci数列的实现为例

创建VS2015的WIN32控制台程序,创建Fibonacci类,构造析构函数默认即可,声明递归与非递归计算方法;Fibonacci.h文件具体实现: 详细实现的方法在Fibonacci.cpp中:...
  • zzcc209
  • zzcc209
  • 2017-05-06 13:14:30
  • 360

单元测试简单入门总结

先说一下今天的简单总结: 用JUnit跑单元测试,首先得有JUnit包,有工程需要的其他包。 而在eclipse中默认不会包含测试包,所以需要引入。其次,如果是maven工程,本地的包可能不全,要将依...
  • shoren80
  • shoren80
  • 2014-10-26 00:57:21
  • 1772

junit4单元测试总结

junit4单元测试总结 本文开发环境为myeclipse10.7 1.  准备工作 1.1. 选择需要单元测试的文件 创建maven工程,右击需要单元测试的文件,选择New->other,选...
  • bejustice
  • bejustice
  • 2014-11-06 16:58:55
  • 1180

android activity 单元测试总结

一、android测试类--Method setUp in android.test.AndroidTestCase not mocked 在build.gradle添加下面 t...
  • liuhu767
  • liuhu767
  • 2017-12-21 10:57:22
  • 58

JAVA 单元测试总结

单元测试的重要性这里就不说了,直接进入正题。很多程序员不喜欢写单元测试,导致项目经常会花很多时间去debug,这完全得不偿失。对关键方法进行单元测试,可以在早期业务逻辑还没那么复杂的时候,尽快排除症结...
  • antony9118
  • antony9118
  • 2017-01-10 12:42:29
  • 7920
收藏助手
不良信息举报
您举报文章:单元测试总结
举报原因:
原因补充:

(最多只允许输入30个字)