service test with PowerMockito
@ RunWith (PowerMockRunner .class )
@ PrepareForTest ({ProductServiceImpl .class , ProductGenerator .class , Product .class })
public class ProductServiceImplTest {
@ Mock
private ProductRepo productRepo ;
@ Mock
private EventBus eventBus ;
@ Rule
private ExpectedException exception = ExpectedException .none ();
private ProductServiceImpl productService ;
@ Before
public void init (){
productService = spy (new ProductServiceImpl (productRepo , eventBus ));
//Whitebox.setInternalState(productService, "productRepo", productRepo); //当为private时
}
}
@PrepareForTest: 包含静态方法的类、待测试的类等
待测试类要spy,而不是用mock。 另外,@InjectMocks不支持mock自身方法。当内部字段为private时,采用WhiteBox来设置内部状态
异常验证可以用@Test(expected=Xxx.class), 但要深入时,用@Rule ExpectedException。
when (productRepo .save (product )).thenReturn (product );
doReturn (new Product ()).when (productService ).findByName ("p1" );
doReturn (new Product ()).when (productService , "findByNo" , "n1" );
doNothing ().when (productService , "checkCategoryId" , 0L );
doThrow (new RuntimeException ("category.invalid" )).when (productService , "checkCategoryId" , 0L );
suppress static constructor:
@ SuppressStaticInitializationFor ("top.zhacker.testdriven.product.model.Product" )
suppress instance constructor:
suppress (constructor (Product .class ));
suppress (method (Product .class ,"check" , Product .class ));
mockStatic (ProductGenerator .class ); when (ProductGenerator .getNextId ()).thenReturn ("no" );
mockStatic (Product .class ); doNothing ().when (Product .class , "check" , any ());
mockStatic (Product .class ); doThrow (new RuntimeException ("check.fail" )).when (Product .class , "check" , any ());
whenNew (Product .class ).withArguments ("invalid" ).thenReturn (mock (Product .class ));
when (productRepo .findByName (any ())).then (invocationOnMock ->{
String name = invocationOnMock .getArgument (0 );
if (name .startsWith ("pa" )) return new Product ("pa" );
if (name .startsWith ("pb" )) return new Product ("pb" );
return null ;
});
exception .expect (RuntimeException .class );
exception .expectMessage ("check.fail" );
verify (productRepo ).save ((Product )argThat (p ->{ //overload
Product toSave = (Product )p ; //overload
assertEquals ("pa" , toSave .getName ());
assertNotNull (toSave .getCreatedAt ());
assertNotNull (toSave .getNo ());
assertNotNull (toSave .getUrl ());
return true ;
}));
verifyPrivate (productService ).invoke ("updateProduct" , product );
verifyStatic (times (1 )); Product .check (product ); // invoke static verify, important