最新消息:天气越来越冷,记得加一件厚衣裳

PowerMock – 局部变量与方法

Java w3sun 21079浏览 0评论

引言

Power Mock提供了强大的Mock能力,其中一个体现就是局部Mock变量,而一般情况下在做单元测试的时候我们无法触碰到局部变量。同时其也支持对私有方法、静态方法、final修饰方法的Mock。

Mock变量

Mock局部变量

为了更好的说明局部变量的Mock,需要对Dao层和Service层稍微做出一些修改:

Book

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
private String name;
private Double price;
}
@Data @NoArgsConstructor @AllArgsConstructor public class Book { private String name; private Double price; }
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
  private String name;
  private Double price;
}

BookDao

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public class BookDao {
public int count() {
throw new UnsupportedOperationException("BookDao does not support count() operation.");
}
public void insert(Book book) {
throw new UnsupportedOperationException("BookDao does not support insert() operation.");
}
}
public class BookDao { public int count() { throw new UnsupportedOperationException("BookDao does not support count() operation."); } public void insert(Book book) { throw new UnsupportedOperationException("BookDao does not support insert() operation."); } }
public class BookDao {
  public int count() {
    throw new UnsupportedOperationException("BookDao does not support count() operation.");
  }

  public void insert(Book book) {
    throw new UnsupportedOperationException("BookDao does not support insert() operation.");
  }
}

BookService

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@Data
@NoArgsConstructor
public class BookService {
public int count() {
BookDao bookDao = new BookDao();
return bookDao.count();
}
public void save(Book book) {
BookDao bookDao = new BookDao();
System.out.println("...BookService save book...");
bookDao.insert(book);
}
}
@Data @NoArgsConstructor public class BookService { public int count() { BookDao bookDao = new BookDao(); return bookDao.count(); } public void save(Book book) { BookDao bookDao = new BookDao(); System.out.println("...BookService save book..."); bookDao.insert(book); } }
@Data
@NoArgsConstructor
public class BookService {

  public int count() {
    BookDao bookDao = new BookDao();
    return bookDao.count();
  }

  public void save(Book book) {
    BookDao bookDao = new BookDao();
    System.out.println("...BookService save book...");
    bookDao.insert(book);
  }
}

BookServiceTestWithPowerMock

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
//定义使用的Runner类型与需要准备的测试类
@RunWith(PowerMockRunner.class)
@PrepareForTest(BookService.class)
public class BookServiceTestWithPowerMock {
@Test
public void count() throws Exception {
//Mock对象,也可以使用 org.mockito.Mock 注解标记来实现
BookDao bookDao = PowerMockito.mock(BookDao.class);
//录制bookDao的行为以便后续进行回放,具体含义为:当bookDao执行count()时返回一个数值15
PowerMockito.when(bookDao.count()).thenReturn(15);
//录制行为,在创建BookDao实例时,不管参数如何都返回上述mock的bookDao
PowerMockito.whenNew(BookDao.class).withAnyArguments().thenReturn(bookDao);
//创建Service实例
BookService bookService = new BookService();
//执行bookService.count()时会在其中回放第一步录制的行为,也就是说会拿到bookDao.count()返回的值20.
int count = bookService.count();
//断言结果,同时verify是否执行了BookDao的count()方法
Assert.assertEquals(15, count);
Mockito.verify(bookDao).count();
}
@Test
public void save() throws Exception {
//创建Book实例
Book book = new Book("C++ Primer", 30.5);
//Mock对象,也可以使用 org.mockito.Mock 注解标记来实现
BookDao bookDao = PowerMockito.mock(BookDao.class);
//录制bookDao的行为以便后续进行回放,insert为void类型,没有返回值。由于具体含义为:当bookDao执行insert(book)什么也不做.
PowerMockito.doNothing().when(bookDao).insert(book);
//录制行为,在创建BookDao实例时,不管参数如何都返回上述mock的bookDao
PowerMockito.whenNew(BookDao.class).withAnyArguments().thenReturn(bookDao);
//创建Service实例
BookService bookService = new BookService();
//执行保存操作
bookService.save(book);
//验证Mock BookDao对象insert方法没有被调用
Mockito.verify(bookDao).insert(book);
}
}
//定义使用的Runner类型与需要准备的测试类 @RunWith(PowerMockRunner.class) @PrepareForTest(BookService.class) public class BookServiceTestWithPowerMock { @Test public void count() throws Exception { //Mock对象,也可以使用 org.mockito.Mock 注解标记来实现 BookDao bookDao = PowerMockito.mock(BookDao.class); //录制bookDao的行为以便后续进行回放,具体含义为:当bookDao执行count()时返回一个数值15 PowerMockito.when(bookDao.count()).thenReturn(15); //录制行为,在创建BookDao实例时,不管参数如何都返回上述mock的bookDao PowerMockito.whenNew(BookDao.class).withAnyArguments().thenReturn(bookDao); //创建Service实例 BookService bookService = new BookService(); //执行bookService.count()时会在其中回放第一步录制的行为,也就是说会拿到bookDao.count()返回的值20. int count = bookService.count(); //断言结果,同时verify是否执行了BookDao的count()方法 Assert.assertEquals(15, count); Mockito.verify(bookDao).count(); } @Test public void save() throws Exception { //创建Book实例 Book book = new Book("C++ Primer", 30.5); //Mock对象,也可以使用 org.mockito.Mock 注解标记来实现 BookDao bookDao = PowerMockito.mock(BookDao.class); //录制bookDao的行为以便后续进行回放,insert为void类型,没有返回值。由于具体含义为:当bookDao执行insert(book)什么也不做. PowerMockito.doNothing().when(bookDao).insert(book); //录制行为,在创建BookDao实例时,不管参数如何都返回上述mock的bookDao PowerMockito.whenNew(BookDao.class).withAnyArguments().thenReturn(bookDao); //创建Service实例 BookService bookService = new BookService(); //执行保存操作 bookService.save(book); //验证Mock BookDao对象insert方法没有被调用 Mockito.verify(bookDao).insert(book); } }
//定义使用的Runner类型与需要准备的测试类
@RunWith(PowerMockRunner.class)
@PrepareForTest(BookService.class)
public class BookServiceTestWithPowerMock {

  @Test
  public void count() throws Exception {
    //Mock对象,也可以使用 org.mockito.Mock 注解标记来实现
    BookDao bookDao = PowerMockito.mock(BookDao.class);
    //录制bookDao的行为以便后续进行回放,具体含义为:当bookDao执行count()时返回一个数值15
    PowerMockito.when(bookDao.count()).thenReturn(15);
    //录制行为,在创建BookDao实例时,不管参数如何都返回上述mock的bookDao
    PowerMockito.whenNew(BookDao.class).withAnyArguments().thenReturn(bookDao);
    //创建Service实例
    BookService bookService = new BookService();
    //执行bookService.count()时会在其中回放第一步录制的行为,也就是说会拿到bookDao.count()返回的值20.
    int count = bookService.count();
    //断言结果,同时verify是否执行了BookDao的count()方法
    Assert.assertEquals(15, count);
    Mockito.verify(bookDao).count();
  }

  @Test
  public void save() throws Exception {
    //创建Book实例
    Book book = new Book("C++ Primer", 30.5);
    //Mock对象,也可以使用 org.mockito.Mock 注解标记来实现
    BookDao bookDao = PowerMockito.mock(BookDao.class);
    //录制bookDao的行为以便后续进行回放,insert为void类型,没有返回值。由于具体含义为:当bookDao执行insert(book)什么也不做.
    PowerMockito.doNothing().when(bookDao).insert(book);
    //录制行为,在创建BookDao实例时,不管参数如何都返回上述mock的bookDao
    PowerMockito.whenNew(BookDao.class).withAnyArguments().thenReturn(bookDao);
    //创建Service实例
    BookService bookService = new BookService();
    //执行保存操作
    bookService.save(book);
    //验证Mock BookDao对象insert方法没有被调用
    Mockito.verify(bookDao).insert(book);
  }
}

可以看到BookDao被成功Mock并且在BookService层的测试中也打印了我们期望的结果。

Mock方法

Mock静态方法

有时候代码中需要调用某个静态工具类指定的方法,如果这个方法非常复杂或者依赖了一些其他组件或者服务, 而我们希望”屏蔽”掉该函数的真实调用情况而代码能够继续运行下去, 那么可以对该静态方法进行Mock。为此我们需要对BookDao做出一些轻微的修改将其中的方法静态化以便我们进行测试。

BookDao
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public class BookDao {
public static int count() {
throw new UnsupportedOperationException("BookDao does not support count() operation.");
}
public static void insert(Book book) {
throw new UnsupportedOperationException("BookDao does not support insert() operation.");
}
}
public class BookDao { public static int count() { throw new UnsupportedOperationException("BookDao does not support count() operation."); } public static void insert(Book book) { throw new UnsupportedOperationException("BookDao does not support insert() operation."); } }
public class BookDao {
  public static int count() {
    throw new UnsupportedOperationException("BookDao does not support count() operation.");
  }

  public static void insert(Book book) {
    throw new UnsupportedOperationException("BookDao does not support insert() operation.");
  }
}
BookService
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@NoArgsConstructor
public class BookService {
public int count() {
return BookDao.count();
}
public void save(Book book) {
System.out.println("......BookService save book......");
BookDao.insert(book);
}
}
@NoArgsConstructor public class BookService { public int count() { return BookDao.count(); } public void save(Book book) { System.out.println("......BookService save book......"); BookDao.insert(book); } }
@NoArgsConstructor
public class BookService {

  public int count() {
    return BookDao.count();
  }

  public void save(Book book) {
    System.out.println("......BookService save book......");
    BookDao.insert(book);
  }
}
BookServiceTestWithPowerMock
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
/定义使用的Runner类型,同时需要用注释的形式将需要测试的静态方法提供给 PowerMockPrepareForTest可以加在指定的方法上.
@RunWith(PowerMockRunner.class)
@PrepareForTest({BookService.class, BookDao.class})
public class BookServiceTestWithPowerMock {
@Test
public void count() {
//Mock静态方法所在的类
PowerMockito.mockStatic(BookDao.class);
//录制bookDao的行为以便后续进行回放,具体含义为:当bookDao执行count()时返回一个数值10.
PowerMockito.when(BookDao.count()).thenReturn(10);
//创建Service实例
BookService bookService = new BookService();
//执行bookService.count()时会在其中回放第一步录制的行为,也就是说会拿到bookDao.count()返回的值20.
int bookCount = bookService.count();
//断言结果,同时verify是否执行了BookDao的count()方法
Assert.assertEquals(10, bookCount);
}
@Test
public void save() {
//创建Book实例
Book book = new Book();
//Mock静态方法所在的类
PowerMockito.mockStatic(BookDao.class);
//录制bookDao的行为以便后续进行回放,insert为void类型,没有返回值。由于具体含义为:当bookDao执行insert(book)什么也不做.
PowerMockito.doNothing().when(BookDao.class);
//创建Service实例
BookService bookService = new BookService();
//执行保存操作
bookService.save(book);
//验证Mock BookDao对象insert方法没有被调用
PowerMockito.verifyStatic();
}
}
/定义使用的Runner类型,同时需要用注释的形式将需要测试的静态方法提供给 PowerMockPrepareForTest可以加在指定的方法上. @RunWith(PowerMockRunner.class) @PrepareForTest({BookService.class, BookDao.class}) public class BookServiceTestWithPowerMock { @Test public void count() { //Mock静态方法所在的类 PowerMockito.mockStatic(BookDao.class); //录制bookDao的行为以便后续进行回放,具体含义为:当bookDao执行count()时返回一个数值10. PowerMockito.when(BookDao.count()).thenReturn(10); //创建Service实例 BookService bookService = new BookService(); //执行bookService.count()时会在其中回放第一步录制的行为,也就是说会拿到bookDao.count()返回的值20. int bookCount = bookService.count(); //断言结果,同时verify是否执行了BookDao的count()方法 Assert.assertEquals(10, bookCount); } @Test public void save() { //创建Book实例 Book book = new Book(); //Mock静态方法所在的类 PowerMockito.mockStatic(BookDao.class); //录制bookDao的行为以便后续进行回放,insert为void类型,没有返回值。由于具体含义为:当bookDao执行insert(book)什么也不做. PowerMockito.doNothing().when(BookDao.class); //创建Service实例 BookService bookService = new BookService(); //执行保存操作 bookService.save(book); //验证Mock BookDao对象insert方法没有被调用 PowerMockito.verifyStatic(); } }
/定义使用的Runner类型,同时需要用注释的形式将需要测试的静态方法提供给 PowerMockPrepareForTest可以加在指定的方法上.
@RunWith(PowerMockRunner.class)
@PrepareForTest({BookService.class, BookDao.class})
public class BookServiceTestWithPowerMock {

  @Test
  public void count() {
    //Mock静态方法所在的类
    PowerMockito.mockStatic(BookDao.class);
    //录制bookDao的行为以便后续进行回放,具体含义为:当bookDao执行count()时返回一个数值10.
    PowerMockito.when(BookDao.count()).thenReturn(10);
    //创建Service实例
    BookService bookService = new BookService();
    //执行bookService.count()时会在其中回放第一步录制的行为,也就是说会拿到bookDao.count()返回的值20.
    int bookCount = bookService.count();
    //断言结果,同时verify是否执行了BookDao的count()方法
    Assert.assertEquals(10, bookCount);
  }

  @Test
  public void save() {
    //创建Book实例
    Book book = new Book();
    //Mock静态方法所在的类
    PowerMockito.mockStatic(BookDao.class);
    //录制bookDao的行为以便后续进行回放,insert为void类型,没有返回值。由于具体含义为:当bookDao执行insert(book)什么也不做.
    PowerMockito.doNothing().when(BookDao.class);
    //创建Service实例
    BookService bookService = new BookService();
    //执行保存操作
    bookService.save(book);
    //验证Mock BookDao对象insert方法没有被调用
    PowerMockito.verifyStatic();
  }
}

Mock final修饰的方法

Book

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
private String name;
private Double price;
}
@Data @NoArgsConstructor @AllArgsConstructor public class Book { private String name; private Double price; }
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
  private String name;
  private Double price;
}

BookDao

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public class BookDao {
public int count() {
throw new UnsupportedOperationException("BookDao does not support count() operation.");
}
public void insert(Book book) {
throw new UnsupportedOperationException("BookDao does not support insert() operation.");
}
public final boolean stored(Book book) {
System.out.println("......confirm whether specified book is stored by BookDao......");
return true;
}
}
public class BookDao { public int count() { throw new UnsupportedOperationException("BookDao does not support count() operation."); } public void insert(Book book) { throw new UnsupportedOperationException("BookDao does not support insert() operation."); } public final boolean stored(Book book) { System.out.println("......confirm whether specified book is stored by BookDao......"); return true; } }
public class BookDao {
  public int count() {
    throw new UnsupportedOperationException("BookDao does not support count() operation.");
  }

  public void insert(Book book) {
    throw new UnsupportedOperationException("BookDao does not support insert() operation.");
  }

  public final boolean stored(Book book) {
    System.out.println("......confirm whether specified book is stored by BookDao......");
    return true;
  }
}

BookService

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@Data
@NoArgsConstructor
public class BookService {
private BookDao bookDao;
public int count() {
return bookDao.count();
}
public void save(Book book) {
System.out.println("......BookService save book......");
bookDao.insert(book);
}
public final boolean stored(Book book) {
System.out.println("......confirm whether specified book is stored by BookService......");
return bookDao.stored(book);
}
}
@Data @NoArgsConstructor public class BookService { private BookDao bookDao; public int count() { return bookDao.count(); } public void save(Book book) { System.out.println("......BookService save book......"); bookDao.insert(book); } public final boolean stored(Book book) { System.out.println("......confirm whether specified book is stored by BookService......"); return bookDao.stored(book); } }
@Data
@NoArgsConstructor
public class BookService {

  private BookDao bookDao;

  public int count() {
    return bookDao.count();
  }

  public void save(Book book) {
    System.out.println("......BookService save book......");
    bookDao.insert(book);
  }

  public final boolean stored(Book book) {
    System.out.println("......confirm whether specified book is stored by BookService......");
    return bookDao.stored(book);
  }
}

BookServiceTestWitPowerMock

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@RunWith(PowerMockRunner.class)
@PrepareForTest({BookService.class, BookDao.class})
public class BookServiceTestWitPowerMock {
@Test
public void isStored() {
//mock一个Book实例.
Book book = PowerMockito.mock(Book.class);
//mock一个BookDao实例.
BookDao bookDao = PowerMockito.mock(BookDao.class);
//录制bookDao的行为以便后续进行回放,具体含义为:当bookDao执行stored()时返回一个数值10.
PowerMockito.when(bookDao.stored(book)).thenReturn(false);
//mock一个BookService实例.
BookService bookService = PowerMockito.mock(BookService.class);
//设置service层中的dao.
bookService.setBookDao(bookDao);
//调用store()判断书籍是否存在.
boolean stored = bookService.stored(book);
//断言返回结果
Assert.assertFalse(stored);
}
}
@RunWith(PowerMockRunner.class) @PrepareForTest({BookService.class, BookDao.class}) public class BookServiceTestWitPowerMock { @Test public void isStored() { //mock一个Book实例. Book book = PowerMockito.mock(Book.class); //mock一个BookDao实例. BookDao bookDao = PowerMockito.mock(BookDao.class); //录制bookDao的行为以便后续进行回放,具体含义为:当bookDao执行stored()时返回一个数值10. PowerMockito.when(bookDao.stored(book)).thenReturn(false); //mock一个BookService实例. BookService bookService = PowerMockito.mock(BookService.class); //设置service层中的dao. bookService.setBookDao(bookDao); //调用store()判断书籍是否存在. boolean stored = bookService.stored(book); //断言返回结果 Assert.assertFalse(stored); } }
@RunWith(PowerMockRunner.class)
@PrepareForTest({BookService.class, BookDao.class})
public class BookServiceTestWitPowerMock {
  @Test
  public void isStored() {
    //mock一个Book实例.
    Book book = PowerMockito.mock(Book.class);
    //mock一个BookDao实例.
    BookDao bookDao = PowerMockito.mock(BookDao.class);
    //录制bookDao的行为以便后续进行回放,具体含义为:当bookDao执行stored()时返回一个数值10.
    PowerMockito.when(bookDao.stored(book)).thenReturn(false);
    //mock一个BookService实例.
    BookService bookService = PowerMockito.mock(BookService.class);
    //设置service层中的dao.
    bookService.setBookDao(bookDao);
    //调用store()判断书籍是否存在.
    boolean stored = bookService.stored(book);
    //断言返回结果
    Assert.assertFalse(stored);
  }
}

Mock构造方法

构造方法分为有参构造和无参构造两种,分别使用:

PowerMockito.whenNew(X.class).withArguments().thenReturn(X instance)

PowerMockito.whenNew(X.class).withAnyArguments().thenReturn(X instance)或者PowerMockito.whenNew(X.class).withNoArguments().thenReturn(X instance)来实现:

Book

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
private String name;
private Double price;
}
@Data @NoArgsConstructor @AllArgsConstructor public class Book { private String name; private Double price; }
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
  private String name;
  private Double price;
}

BookDao

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public class BookDao {
public int count() {
throw new UnsupportedOperationException("BookDao does not support count() operation.");
}
public void insert(Book book) {
throw new UnsupportedOperationException("BookDao does not support insert() operation.");
}
}
public class BookDao { public int count() { throw new UnsupportedOperationException("BookDao does not support count() operation."); } public void insert(Book book) { throw new UnsupportedOperationException("BookDao does not support insert() operation."); } }
public class BookDao {
  public  int count() {
    throw new UnsupportedOperationException("BookDao does not support count() operation.");
  }

  public void insert(Book book) {
    throw new UnsupportedOperationException("BookDao does not support insert() operation.");
  }
}

BookService

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BookService {
private BookDao bookDao;
public int count() {
return bookDao.count();
}
public void save(Book book) {
System.out.println("BookService save book.");
bookDao.insert(book);
}
}
@Data @NoArgsConstructor @AllArgsConstructor public class BookService { private BookDao bookDao; public int count() { return bookDao.count(); } public void save(Book book) { System.out.println("BookService save book."); bookDao.insert(book); } }
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BookService {
  private BookDao bookDao;

  public int count() {
    return bookDao.count();
  }

  public void save(Book book) {
    System.out.println("BookService save book.");
    bookDao.insert(book);
  }
}

BookServiceTestWitPowerMock

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
//定义使用的Runner类型,同时需要用注释的形式将需要测试的静态方法提供给 PowerMockPrepareForTest可以加在指定的方法上.
@RunWith(PowerMockRunner.class)
@PrepareForTest({BookService.class, BookDao.class})
public class BookServiceTestWitPowerMock {
@Test
public void save() throws Exception {
String name = "C++ Primer";
Double price = 20.6;
//Mock一个BookDao实例.
BookDao bookDao = PowerMockito.mock(BookDao.class);
//Mock一个Book实例.
Book book = PowerMockito.mock(Book.class);
//录制行为,在创建Book实例时,根据name和price参数构建一个book实例并返回.
PowerMockito.whenNew(Book.class).withArguments(name, price).thenReturn(book);
//录制行为,在创建BookDao实例时,不管参数如何都返回上述mock的bookDao.
PowerMockito.whenNew(BookDao.class).withAnyArguments().thenReturn(bookDao);
//录制bookDao的行为以便后续进行回放,insert为void类型,没有返回值。由于具体含义为:当bookDao执行insert(book)什么也不做.
PowerMockito.doNothing().when(bookDao).insert(book);
BookService bookService = new BookService(bookDao);
//执行保存操作
bookService.save(book);
//验证Mock BookDao对象insert方法没有被调用
Mockito.verify(bookDao).insert(book);
System.out.println(book.getClass());
System.out.println(bookDao.getClass());
}
}
//定义使用的Runner类型,同时需要用注释的形式将需要测试的静态方法提供给 PowerMockPrepareForTest可以加在指定的方法上. @RunWith(PowerMockRunner.class) @PrepareForTest({BookService.class, BookDao.class}) public class BookServiceTestWitPowerMock { @Test public void save() throws Exception { String name = "C++ Primer"; Double price = 20.6; //Mock一个BookDao实例. BookDao bookDao = PowerMockito.mock(BookDao.class); //Mock一个Book实例. Book book = PowerMockito.mock(Book.class); //录制行为,在创建Book实例时,根据name和price参数构建一个book实例并返回. PowerMockito.whenNew(Book.class).withArguments(name, price).thenReturn(book); //录制行为,在创建BookDao实例时,不管参数如何都返回上述mock的bookDao. PowerMockito.whenNew(BookDao.class).withAnyArguments().thenReturn(bookDao); //录制bookDao的行为以便后续进行回放,insert为void类型,没有返回值。由于具体含义为:当bookDao执行insert(book)什么也不做. PowerMockito.doNothing().when(bookDao).insert(book); BookService bookService = new BookService(bookDao); //执行保存操作 bookService.save(book); //验证Mock BookDao对象insert方法没有被调用 Mockito.verify(bookDao).insert(book); System.out.println(book.getClass()); System.out.println(bookDao.getClass()); } }
//定义使用的Runner类型,同时需要用注释的形式将需要测试的静态方法提供给 PowerMockPrepareForTest可以加在指定的方法上.
@RunWith(PowerMockRunner.class)
@PrepareForTest({BookService.class, BookDao.class})
public class BookServiceTestWitPowerMock {
  @Test
  public void save() throws Exception {
    String name = "C++ Primer";
    Double price = 20.6;
    //Mock一个BookDao实例.
    BookDao bookDao = PowerMockito.mock(BookDao.class);
    //Mock一个Book实例.
    Book book = PowerMockito.mock(Book.class);
    //录制行为,在创建Book实例时,根据name和price参数构建一个book实例并返回.
    PowerMockito.whenNew(Book.class).withArguments(name, price).thenReturn(book);
    //录制行为,在创建BookDao实例时,不管参数如何都返回上述mock的bookDao.
    PowerMockito.whenNew(BookDao.class).withAnyArguments().thenReturn(bookDao);
    //录制bookDao的行为以便后续进行回放,insert为void类型,没有返回值。由于具体含义为:当bookDao执行insert(book)什么也不做.
    PowerMockito.doNothing().when(bookDao).insert(book);
    BookService bookService = new BookService(bookDao);
    //执行保存操作
    bookService.save(book);
    //验证Mock BookDao对象insert方法没有被调用
    Mockito.verify(bookDao).insert(book);
    System.out.println(book.getClass());
    System.out.println(bookDao.getClass());
  }
}

最后打印的BookService层方法信息,Book和BookDao实例信息分别为:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
BookService save book.
class com.w3sun.mock.method.construct.bean.Book$$EnhancerByMockitoWithCGLIB$$b1ce93f9
class com.w3sun.mock.method.construct.dao.BookDao$$EnhancerByMockitoWithCGLIB$$e7eecb6f
BookService save book. class com.w3sun.mock.method.construct.bean.Book$$EnhancerByMockitoWithCGLIB$$b1ce93f9 class com.w3sun.mock.method.construct.dao.BookDao$$EnhancerByMockitoWithCGLIB$$e7eecb6f
BookService save book.
class com.w3sun.mock.method.construct.bean.Book$$EnhancerByMockitoWithCGLIB$$b1ce93f9
class com.w3sun.mock.method.construct.dao.BookDao$$EnhancerByMockitoWithCGLIB$$e7eecb6f

其实PowerMock在mock实例的过程中使用CGLIB进行代理,详细信息可以参考:https://github.com/cglib/cglib/wiki

Mock私有方法

BookService

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public class BookService {
public boolean exist(String name) {
return checkExist(name);
}
private boolean checkExist(String name) {
System.out.println("---BookService checkExist---");
throw new UnsupportedOperationException("UserService checkExist unsupported exception.");
}
}
public class BookService { public boolean exist(String name) { return checkExist(name); } private boolean checkExist(String name) { System.out.println("---BookService checkExist---"); throw new UnsupportedOperationException("UserService checkExist unsupported exception."); } }
public class BookService {

  public boolean exist(String name) {
    return checkExist(name);
  }

  private boolean checkExist(String name) {
    System.out.println("---BookService checkExist---");
    throw new UnsupportedOperationException("UserService checkExist unsupported exception.");
  }
}

BookServiceTestWitPowerMock

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
//定义使用的Runner类型,同时需要用注释的形式将需要测试的静态方法提供给 PowerMockPrepareForTest可以加在指定的方法上.
@RunWith(PowerMockRunner.class)
@PrepareForTest(BookService.class)
public class BookServiceTestWithPowerMock {
@Test
public void exist() throws Exception {
String arg = "yidian.io";
//如果使用spy且不满足断言的情况下将会调用真正的方法,否则调用mock的方法。
BookService bookService = PowerMockito.spy(new BookService());
//录制行为,在调用BookService的checkExist方法且在传入参数为yidian.io时返回true
PowerMockito.doReturn(true)
.when(bookService, "checkExist", arg);
//调用方法
boolean exist = bookService.exist(arg);
//断言结果
Assert.assertTrue(exist);
System.out.println("==============");
try {
//如果调用了bookService.exist且传入的参数与录入时指定参数不一致时则会调用真实的方法
bookService.exist("yidian");
fail("Process here will be error.");
} catch (Exception e) {
Assert.assertTrue(e instanceof UnsupportedOperationException);
}
}
}
//定义使用的Runner类型,同时需要用注释的形式将需要测试的静态方法提供给 PowerMockPrepareForTest可以加在指定的方法上. @RunWith(PowerMockRunner.class) @PrepareForTest(BookService.class) public class BookServiceTestWithPowerMock { @Test public void exist() throws Exception { String arg = "yidian.io"; //如果使用spy且不满足断言的情况下将会调用真正的方法,否则调用mock的方法。 BookService bookService = PowerMockito.spy(new BookService()); //录制行为,在调用BookService的checkExist方法且在传入参数为yidian.io时返回true PowerMockito.doReturn(true) .when(bookService, "checkExist", arg); //调用方法 boolean exist = bookService.exist(arg); //断言结果 Assert.assertTrue(exist); System.out.println("=============="); try { //如果调用了bookService.exist且传入的参数与录入时指定参数不一致时则会调用真实的方法 bookService.exist("yidian"); fail("Process here will be error."); } catch (Exception e) { Assert.assertTrue(e instanceof UnsupportedOperationException); } } }
//定义使用的Runner类型,同时需要用注释的形式将需要测试的静态方法提供给 PowerMockPrepareForTest可以加在指定的方法上.
@RunWith(PowerMockRunner.class)
@PrepareForTest(BookService.class)
public class BookServiceTestWithPowerMock {

  @Test
  public void exist() throws Exception {
    String arg = "yidian.io";
    //如果使用spy且不满足断言的情况下将会调用真正的方法,否则调用mock的方法。
    BookService bookService = PowerMockito.spy(new BookService());
    //录制行为,在调用BookService的checkExist方法且在传入参数为yidian.io时返回true
    PowerMockito.doReturn(true)
        .when(bookService, "checkExist", arg);
    //调用方法
    boolean exist = bookService.exist(arg);
    //断言结果
    Assert.assertTrue(exist);
    System.out.println("==============");
    try {
      //如果调用了bookService.exist且传入的参数与录入时指定参数不一致时则会调用真实的方法
      bookService.exist("yidian");
      fail("Process here will be error.");
    } catch (Exception e) {
      Assert.assertTrue(e instanceof UnsupportedOperationException);
    }
  }
}

参考资料

转载请注明:雪后西塘 » PowerMock – 局部变量与方法

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址