单元测试 Mockito PowerMockito

自己写单元测试时的总结:

  1. 静态方法:
 在类上添加
@RunWith(PowerMockRunner.class)
@PrepareForTest({StaticTest.class})
方法:
PowerMockito.mockStatic(StaticTest.class);  
PowerMockito.when(StaticTest.static1()).thenReturn("static");    // 方法的参数尽量一致
PowerMockito.doNothing().when(StaticTest.class, "static1", file, null);
String result = StaticTest.static1();  

如果mockStatic的类存在static代码块, 则mock的时候会先执行static代码块中的内容, 然后再mock, 所以需要将static里面的内容也mock

  1. mockito的基本格式
@InjectMocks
@Spy
private AccountInfoController fixture = new AccountInfoController();
@Mock
private AccountInfoService accountInfoService;
@Mock
private HttpServletRequest request;
@Before
public void setUp() throws Exception {
	MockitoAnnotations.initMocks(this);
}
doReturn(map).when(accountInfoService).addAccountInfo("a", "user", 0, 1, "xxx", "opera", 1, 1);
  1. new:
File file = new File(path);
return file.exists();
模拟:
@RunWith(PowerMockRunner.class)
@PrepareForTest(必须是**待测试方法所在的类**.class)
File file = PowerMockito.mock(File.class);
PowerMockito.whenNew(File.class).withArguments("bbb").thenReturn(file);
PowerMockito.whenNew(File.class).withArguments(Mockito.anyString()).thenReturn(file);
PowerMockito.whenNew(File.class).withAnyArguments().thenReturn(file);
PowerMockito.when(file.exists()).thenReturn(true);
注: 待测试方法的意思是: 比如测试A类中的methodB()方法,则prepareForTest里包含A.class, 而不是A的测试类
  1. void:
PowerMockito.doNothing().when(casService).addSupplier(anyLong(), any(ServiceKey.class));
  1. 抽象类:
BaseTransaction baseTransaction = Mockito.mock(BaseTransaction.class, Mockito.CALLS_REAL_METHODS);
  1. @Mock与MockitoAnnotations.initMocks(this);

  2. 总结

8. Progress process = Mockito.mock(Progress.class); mock只是mock一个类/接口的对象,
mock出来的对象并不会自动替换掉正式代码里面的对象,你必须要有某种方式把mock对象应用到正式代码里面
9. PasswordValidator spyValidator = Mockito.spy(PasswordValidator.class);
Mockito.when(spyValidator.verifyPassword(anyString())).thenReturn(true);
10. spy与mock的唯一区别就是默认行为不一样:spy对象的方法默认调用真实的逻辑,mock对象的方法默认什么都不做,或直接返回默认值
  1. 总结
 如果mock的方法在多线程中, 则要在test方法中进行休眠处理,防止主线程结束导致多线程没有正常结束
  1. 抛出异常:
PowerMockito.doThrow(new MySelfException("111")).when(object).method(Mockito.anyString(),Mockito.anyInt());
  1. 总结
spy的对象也可以进行mock。mock的方法参数类型必须与实际参数一致,尤其注意null参数
  Mockito.doNothing().when(fixture).addAccountInfo(Mockito.anyString(), Mockito.eq(null));
  1. spy对象的私有属性: 反射获取
Field field = spy类.class.getDeclaredField("a");
field.setAccessible(true); //粗爆的改成可访问,不管现有修饰
field.set(spy对象, 3);
  1. powermockito spy方法 内部调用私有方法
@PrepareForTest({A.class})
PowerMockito.doNothing().when(fixture, "method", Mockito.anyInt(), Mockito.anyString());
PowerMockito.doreturn(***).when(fixture, "method1", Mockito.anyInt(), Mockito.anyString());
  1. mock私有方法: 用反射
private Method privateMethod;
@Before
public void setUp() throws Exception {
	privateMethod = A.class.getDeclaredMethod("privateMethod", Integer.class, String.class);
	privateMethod.setAccessible(true);
}
try {
 privateMethod.invoke(fixture, 1, "1");
 }catch (Exception e) {
	if (e instanceof InvocationTargetException) {
		InvocationTargetException e1 = (InvocationTargetException) e;
		System.out.println(e1.getCause().getMessage());
	} else {
		System.out.println(e.getMessage());
	}
 }
  1. 同时mock一个方法多次, 可以分开调用;如果超过设定次数,则方法取值为最后一个的值
PowerMockito.when(A.method1).thenReturn(result1).thenReturn(result2).thenReturn(result3);
  1. 数组
Mockito.any(String[].class)
  1. HttpClient模拟
private HttpClient mockHttpClient;
private HttpPost mockHttpPost;
private HttpResponse mockHttpResponse;
private HttpEntity mockHttpEntity; 
private InputStream mockInputStream;
private InputStreamReader mockInputStreamReader;
private BufferedReader mockBufferedReader;
ProtocolVersion protocolVersion = new ProtocolVersion("1", 2,1);
StatusLine statusLine = new BasicStatusLine(protocolVersion, 200, "");
PowerMockito.mockStatic(HttpClientBuilder.class);
PowerMockito.when(HttpClientBuilder.create()).thenReturn(mockHttpClientBuilder);
PowerMockito.doReturn(mockHttpClient).when(mockHttpClientBuilder).build();
PowerMockito.doReturn(mockHttpResponse).when(mockHttpClient).execute(Mockito.any(HttpPost.class));
PowerMockito.doReturn(statusLine).when(mockHttpResponse).getStatusLine();
  1. 正常情况(when().then()的比对)
PowerMockito.doThrow(new Exception("111")).when(a).method();
a. PowerMockito.doReturn(null).when(a).method();
b. PowerMockito.when(a.method()).thenReturn(null); 
c. PowerMockito.doThrow(exception).when(mock).someVoidMethod();
d. PowerMockito.doReturn(null).when(a.method()); 
区别:
1. 首先mock对象需要花费时间。
2. 如果mock对象过程结束了,则三个方法可以随便调用,即在setup的方法(@Before)中先初始化mock对象,那么三个方法可以随意调用
3. 如果是在方法内部才开始mock对象,即(Power)Mockito.mock(A.class),那么最好是使用b或c的方法,能保证在mock对象结束后再返回结果,否则会提示UnfinishedStubbingException异常
4. 建议用b方法
5. a和d的区别是,如果a是spy的对象,需要用a 

  1. kafka模拟: 使用kafka自带的MockProducer
MockProducer mockProducer = PowerMockito.mock(MockProducer.class);
Field producer = AlertUtil.class.getDeclaredField("producer");
producer.setAccessible(true);
producer.set(AlertUtil.class, mockProducer);
PowerMockito.when(mockProducer.send(Mockito.any(ProducerRecord.class))).thenReturn(null);
  1. 当涉及文件操作时
a. 需要先创建,然后读取*
File file = new File(this.getClass().getResource("").getFile() + "fileName");
if (!file.exists()) {
	generateFile(file);
} else {
	file.delete();
	generateFile(file);
}
FileInputStream fileInputStream = new FileInputStream(file);
PowerMockito.whenNew(FileInputStream.class).withAnyArguments().thenReturn(fileInputStream);

public void generateFile(File file) {
        Document document = DocumentHelper.createDocument();
        Element rootElement = document.addElement("allocations");
        Element rootQueueElement = rootElement.addElement("queue");
        rootQueueElement.addAttribute("name", "root");
        Element aclSubmitApps = rootQueueElement.addElement("aclSubmitApps");
        aclSubmitApps.addText(" ");
        Element aclAdministerApps = rootQueueElement.addElement("aclAdministerApps");
        aclAdministerApps.addText(" ");

        Element queueChild = rootQueueElement.addElement("queue");
        queueChild.addAttribute("name", "999");

        queueChild.addElement("minResources").setText("1 mb,1 vcores");
        queueChild.addElement("maxResources").setText("1 mb,1 vcores");
        queueChild.addElement("maxRunningApps").setText("1");
        queueChild.addElement("maxAMShare").setText("1");
        queueChild.addElement("aclSubmitApps").setText("1");
        queueChild.addElement("weight").setText("1");
        queueChild.addElement("schedulingPolicy").setText("1");
        XMLWriter writer = null;
        try {
            // 把内存中的dom树 写回到一个xml文件
            OutputFormat format = OutputFormat.createPrettyPrint();
            // 指定XML编码 输出到output.xml
            format.setEncoding("UTF-8");
            format.setTrimText(false);

            writer = new XMLWriter(new FileOutputStream(file), format);
            writer.write(document);
            writer.flush();
        } catch (Exception e) {
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                }
            }
        }
    }

b. 直接将文件写在内存中: 太费事,不好实现,暂时没想到好方法
  1. 总结
a.只要是接口调用,都可以直接mock: PowerMockito.mock(A.class);
b.在一个测试方法中,mock方法是全方法有效,除非是改变方法的方法值,否则不需要再次调用;同理mock的对象也是在方法内一直有效。
c.若mock对象的方法没有设定返回值,那么返回的结果是默认值:单个对象返回的是null,集合返回的是大小为0的集合
d.mock静态类的时候,mockStatic()括号中的类一定要是static方法所在的类,否则可能出现问题(即使继承也不行);非static类可以
  1. mock数据库连接:
Connection connection = PowerMockito.mock(Connection.class);
Statement statement = PowerMockito.mock(Statement.class);
ResultSet resultSet = PowerMockito.mock(ResultSet.class);

PowerMockito.mockStatic(DBConnectUtil.class);
PowerMockito.when(DBConnectUtil.getConnection(null, null, null, null)).thenReturn(connection);
PowerMockito.when(connection.createStatement()).thenReturn(statement);
PowerMockito.when(statement.executeQuery(Mockito.anyString())).thenReturn(resultSet);
PowerMockito.when(resultSet.ne()).thenReturn(true).thenReturn(false);
PowerMockito.when(resultSet.getString(Mockito.anyInt())).thenReturn("1").thenReturn("2");
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值