PowerMockito实践<二>

本文介绍了PowerMockito的高级应用技巧,包括如何为静态方法、私有方法及构造器设桩,以及如何避免常见的错误。同时提供了示例代码帮助理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述:

PowerMockito擅长mock静态类/静态方法/私有方法/构造器


1. 当给spy的类设桩时,最好使用doReturn / doThrow / doNothing(只适应于返回void的方法)等,使用thenReturn/thenThrow可能会产生一些错误,

参考示例代码:testStub4SpyClass;

2. 当给静态方法设桩时,使用thenReturn/ thenThrow, 参考示例代码:verifyStaticMethod1;

3. 如果想验证测试类的private方法, 需要spy测试类,示例代码参考:verifyPrivateMethod;

4. Mockito&PowerMockito无法mock final类和方法;

5. 当使用PowerMockito时, 如果when在末尾, 方法的参数必须是实例,不能是方法调用(如method1(), 当用方法调用时,

mockito会认为是开始stub),当是方法调用的时候会报错:Unfinished-StubbingException; when在thenReturn前没有问题, 

参考代码:verifyTheStubbingOfWhen;

6. 如果想验证构造器,必须在方法执行前为类声明whenNew, 参考代码:verifyConstructor;

7. @PrepareForTest()的参数为Class[], 或String[], 例如:@PreapareForTest(fullyQualifiedNames={"xxx", "xxxxx"}, 源码如下:

public @interface PrepareForTest
{
  public abstract Class<?>[] value();
  public abstract String[] fullyQualifiedNames();
}


示例代码:

package com.ray.mockito_demo1;

import static org.mockito.Mockito.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
// 声明需要测试静态方法/私有方法的类, 可以声明多个,用逗号隔开
@PrepareForTest({ ClassA.class })
public class PowerMockitoDemo3 {

	// /$ begin test ClassA
	@InjectMocks
	private ClassA classA;

	@Test
	public void testStub4SpyClass() throws Exception {
		classA = PowerMockito.spy(classA);
		String task = "跑步";
		// PowerMockito.when(classA, "method2", task).thenReturn("。。。。");
		PowerMockito.doReturn("。。。。").when(classA, "method2", task);

		classA.invokeMethod2(task);
		PowerMockito.verifyPrivate(classA).invoke("method2", task);
	}

	@Test
	public void verifyTheStubbingOfWhen() throws Exception {

		User u1 = mock(User.class);
		when(u1.getName()).thenReturn("张三");

		classA = PowerMockito.spy(classA);
		// 抛出异常UnfinishedStubbingException
		PowerMockito.doReturn("。。。。").when(classA, "method2", u1.getName());
		//正确的方式
		// PowerMockito.doReturn("。。。。").when(classA, "method2", "张三");
		//或者 PowerMockito.when(classA, "method2", u1.getName()).thenReturn("。。。。");
		
		classA.invokeMethod2(u1.getName());
		PowerMockito.verifyPrivate(classA).invoke("method2", u1.getName());
	}

	@Test
	public void verifyStaticMethod1() throws Exception {
		PowerMockito.mockStatic(ClassA.class);
		PowerMockito.spy(ClassA.class);
		PowerMockito.doReturn("hahaha").when(ClassA.class, "staticMethod1");

		ClassA.invokeStaticMethod1();
		PowerMockito.verifyStatic();
		ClassA.staticMethod1();
	}

	@Test
	public void verifyPrivateMethod() throws Exception {
		// 如果不将PowerMockito.spy(classA)赋值给classA, mock将不会生效
		classA = PowerMockito.spy(classA);
		classA.invokeMethod1();
		PowerMockito.verifyPrivate(classA).invoke("method1");
	}
	
	@Test
	public void verifyConstructor() throws Exception{
		User u1 = mock(User.class);
		when(u1.getName()).thenReturn("李四");
		
		//如果没有设置whenNew, 将会报错IllegalStateException... 
		//Note that only expected object creations(e.g. those using whenNew(..)) can be verified
		PowerMockito.whenNew(User.class).withNoArguments().thenReturn(u1);
		
		classA.invokeMethod3();
		PowerMockito.verifyNew(User.class).withNoArguments();		
	}	
}

class ClassA {
	public static void invokeStaticMethod1() {
		System.out.println(staticMethod1());
	}

	public static String staticMethod1() {
		return "test static method1.";
	}

	public void invokeMethod1() {
		method1();
	}

	public void invokeMethod2(String param) {
		System.out.println(method2(param));
	}
	
	public void invokeMethod3(){
		User user = new User();
		user.setName("张三");
		method3(user);
	}
	
	private void method3(User user){
		System.out.println(String.format("Welcome, %s", user.getName()));
	}

	private void method1() {
		System.out.println("method1 executed.");
	}

	private String method2(String task) {
		return String.format("%s executed.", task);
	}
}

class User {
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}


相关jar包:

mvn仓库:http://mvnrepository.com/

<dependencies>
		<dependency>
			<groupId>org.mockito</groupId>
			<artifactId>mockito-all</artifactId>
			<version>1.9.5</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.powermock</groupId>
			<artifactId>powermock-module-junit4</artifactId>
			<version>1.5.5</version>
		</dependency>

		<dependency>
			<groupId>org.powermock</groupId>
			<artifactId>powermock-api-mockito</artifactId>
			<version>1.5.5</version>
		</dependency>
	</dependencies>


public class StarRocksUtils { 16: private static final Logger logger = LoggerFactory.getLogger("StarRocksUtils"); 17: 18: public static String connectionAttributes = ""; 19: public static String url = ""; 20: 21: // 静态块初始化驱动(只加载一次) 22: static { 23: try { 24: Class.forName("com.htsc.bdpt.mariadb.jdbc.Driver"); 25: } catch (ClassNotFoundException e) { 26: throw new RuntimeException("JDBC driver not found", e); 27: } 28: 29: connectionAttributes = Config.getSingleton().getConnectionAttributes(); 30: url = Config.getSingleton().getStarRocksUrl(); 31: } 32: 33: /** 34: * 执行更新操作(自动关闭连接) 35: * @return 受影响的行数,失败返回-1 36: */ 37: public static int executeUpdate(String sql, Consumer<PreparedStatement> paramSetter) { 38: try (Connection conn = DriverManager.getConnection(url, buildConnectionProps()); 39: PreparedStatement pstmt = conn.prepareStatement(sql)) { 40: // 设置参数 41:• if (paramSetter != null) { 42: paramSetter.accept(pstmt); 43: } 44: pstmt.executeUpdate(); 45: return 1; 46: } catch (SQLException e) { 47: logger.error("Execute SQL failed: {}", sql, e); 48: return -1; 49: } 50: } 51: 52: public static Result executeSelect(String sql) { 53: try (Connection conn = DriverManager.getConnection(url, buildConnectionProps()); 54: PreparedStatement pstmt = conn.prepareStatement(sql)) { 55: return new Result<ResultSet>(true,new ErrorContext(200,"操作成功",""),pstmt.executeQuery()); 56: } catch (SQLException e) { 57: logger.error("Execute SQL failed: {}", sql, e); 58: return new Result<List<String>>(false,new ErrorContext(400,e.getMessage(),""),new ArrayList<String>()); 59: } 60: } 61: 62: // 私有方法保证线程安全 63: private static Properties buildConnectionProps() { 64: Properties props = new Properties(); 65: props.setProperty("connectionAttributes", connectionAttributes); 66: return props; 67: } 68: 69: } 单元测试怎么测试对应的 catch 代码块。
03-27
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值