package com.test.mock;
import java.lang.reflect.Field;
import org.junit.Test;
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
import mockit.Deencapsulation;
import mockit.Expectations;
import mockit.Mock;
import mockit.MockUp;
import mockit.Mocked;
import mockit.Mockit;
import mockit.NonStrictExpectations;
import mockit.Verifications;
public class MyServiceTest {
// 模拟方法返回值
@Test
public void testFetchData() throws Exception{
MyService service = mock(MyService.class);
when(service.fetchData(anyString())).thenReturn("123456789");
System.out.println(service.fetchData("test"));
service.setUrl("www.baidu.com");
System.out.println(service.getUrl());
//anyString 任意值
}
// 用反射 设置属性值
@Test
public void testFetch() throws Exception {
MyService service = new MyService();
Field field = service.getClass().getDeclaredField("url");
field.setAccessible(true);
field.set(service, "1111");
System.out.println(service.getUrl());
}
// 模拟属性返回值
@Test
public void testFetchData1() {
MyService service = new MyService();
new Expectations() {
{
Deencapsulation.invoke(MyService.class, "fetchData", "Unmi");
result = "http://unmi.cc";
}
};
String actual = service.fetchData("Unmi");
System.out.println(actual);
System.out.println(service.getUrl());
}
@Mocked //用@Mocked标注的对象,不需要赋值,jmockit自动mock
MyService obj;
@Test
public void testHello() {
new NonStrictExpectations() {//录制预期模拟行为
{
obj.fetchData("Zhangsan");
returns("Hello Zhangsan");
//也可以使用:result = "Hello Zhangsan";
}
};
assertEquals("Hello Zhangsan", obj.fetchData("Zhangsan"));//调用测试方法
new Verifications() {//验证预期Mock行为被调用
{
obj.fetchData("Hello Zhangsan");
times = 1;
}
};
}
@Test
public void testMockNormalMethodContent() throws Exception {
MyService obj = new MyService();
new MockUp<MyService>() {//使用MockUp修改被测试方法内部逻辑
@Mock
public String fetchData(String i) {
return "00";
}
};
System.out.println(obj.fetchData("1"));
System.out.println(obj.getUrl());
assertEquals("00", obj.fetchData("1"));
assertEquals("00", obj.fetchData("1"));
Mockit.tearDownMocks();//注意:在JMockit1.5之后已经没有Mockit这个类,使用MockUp代替,mockUp和tearDown方法在MockUp类中
}
@Mocked
private MyService mt= null;
@Test
public void testJmocked1(){
new Expectations(){
{
mt.getUrl();
result = "www.baidu.com";
mt.fetchData("dd");
result="fafa";
}
};
System.out.println(mt.getUrl());
System.out.println(mt.fetchData("dd"));
}
@Test
public void testJmocked2(){
new NonStrictExpectations(){
{
mt.test();
result=true;
mt.getUrl();
result = "www.baidu.com";
}
};
System.out.println(mt.getUrl());
System.out.println(mt.fetchData("dd"));
System.out.println(mt.test());
}
@Mocked(methods = { "test" }, inverse = false)
// 声明的方法可以使用正则表达式
// methods 代表只有声明的方法才会进行mock, inverse
// 代表是否反转声明,如果inverse=true,那么就是除了声明的方法不mock
private MyService myMethod=new MyService();
@Test
public void testPrivateMethodMock() {
new NonStrictExpectations(new MyService()) {
{
myMethod.test();
result=true;
}
};
System.out.println(myMethod.test());
System.out.println(myMethod.fetchData(""));
}
/*
* 对私有成员变量进行设值的示例
*/
private @Mocked
MyService MyPriv=new MyService();
@Test
public void MockPrivateMethod(){
// 注意:这里使用了动态部分mock
new Expectations(MyPriv) {
{
// 对私有的变量设置值
this.setField(MyPriv, "name", "哈哈");
}
};
System.out.println(MyPriv.getname());
System.out.println(MyPriv.getUrl());
}
@Test
/*
* 对mock类型的私有成员方法进行mock的示例
*/
public void privateAccessMethod() {
// 注意:这里使用了动态部分mock
new Expectations(MyPriv) {
{
// 对私有方法进行mock
this.invoke(MyPriv, "getPriName");
result = "测试私有方法";
}
};
System.out.println(MyPriv.testMockPrivateMethod());
}
/**
* 除了使用@MockUp的另一种基于状态的Mock,随穿随脱?
*
* @author Ginge
*
*/
public static class ConstructorTest2 {
@Mocked
private MyService constructor = new MyService();
@Test
public void mockConstructor() {
// 可以在任意时候把Mock装置起来,不用的时候可以脱下来
Mockit.setUpMock(MyService.class, new MockedConstructor());
// 触发构造方法的mock
constructor=new MyService();
System.out.println(constructor.getname());
// 注意咯,擦亮眼睛了,现在开始脱了
Mockit.tearDownMocks(MyService.class);
constructor = new MyService();
// 看到了吧,看到真容了
System.out.println(constructor.getname());
}
}
/**
* MockedConstructor相当于一个标志,具体名称不重要,重要的要它里面被@Mock注解的方法。如果有方法被注解了@Mock,
* 并且恰好方法的签名又和Mockit.setUpMock中声明的类型中的某个方法一样,那么对应的方法就被Mock
* 为了方便才把这个类的声明放到ConstructorTest2里面的,其实这个类可以放到任何地方
*
* @author Ginge
*
*/
public static class MockedConstructor {
@Mock
public String getname() {
return "mock_Constructor";
}
}
/**
* mock实例中it代表实际的mock对象
* mock对象可以访问实体对象
* @author Ginge
*
*/
public static class AccessRealInstanceTest {
//注意,这里少了@Mocked
private MyService constructor = new MyService();
@Test
public void mockConstructor() {
// 可以在任意时候把Mock装置起来,不用的时候可以脱下来
Mockit.setUpMock(MyService.class, new MockedConstructor());
//参数没有匹配到,直接返回了unknown
System.out.println(constructor.getRealInstanceName("2"));
//参数匹配到1,返回了实际对象方法调用的结果
System.out.println(constructor.getRealInstanceName("1"));
}
/**
* MockedConstructor相当于一个标志,具体名称不重要,重要的是它里面被@Mock注解的方法。如果有方法被注解了@Mock,
* 并且恰好方法的签名又和Mockit.setUpMock中声明的类型中的某个方法一样,那么对应的方法就被Mock
* 为了方便才把这个类的声明放到ConstructorTest2里面的,其实这个类可以放到任何地方
*
* @author Ginge
*
*/
public class MockedConstructor{
//it属性表示实际对象
public MyService it;
@Mock(reentrant = true)//reentrant表示是否可以访问实际对象
public String getRealInstanceName(String m) {
if ("1".equals(m)) {
return it.judgeToOne(m);
} else {
return "unknown";
}
}
}
}
}