引言
周五去面试又被面试的一个问题问哑巴了
面试官:知道框架Mockito吗
我:知道,就是一个测试框架
面试官:哪知道Mockito框架的@mock注解的底层原理吗
我:。。。(哑巴了)
大公司里面测试是非常重要的,几乎占到了开发的二分之一公司,而Mockito框架是Java测试的首选,然后@Mock注解又是Mockito框架里面的重中之重,了解@Mock注解的原理对于Java的测试是非常有帮助的。
先说结果:@Mock注解其实就是借助cglib的动态代理的原理帮我们new了一个@Mock注解作用类的子类
package com.one.util;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Company {
private String name;
public String hh(){
return "字符串";
}
}
User类,mm()的返回值就是Company类的hh()返回值
package com.one.util;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class User {
private Company company;
private int age;
public String mm(){
return company.hh();
}
}
然后UserTest类如下,此时可以看到下面的Company上面放了@Mock注解,他的作用就是帮我们生产一个Company类的子类(假如是CompanyZi),然后使用多态赋值给下面的company(就像这样Company company=new CompanyZi),而且这个ComanyZi类里面的hh()方法的返回值是null,为什么这样说呢,我们看下面的结果
package com.one.util;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.assertj.core.api.Assertions.catchThrowable;
@RunWith(MockitoJUnitRunner.class)
public class UserTest {
@Mock
private Company company;
private User user;
@Before
public void setUp() {
user = new User(company, 1);
}
@Test
public void tt() {
catchThrowable(() -> {
String mm = user.mm();
System.out.println(mm);
});
}
}
package com.one.util;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Company {
private String name;
public String hh(){
return "字符串";
}
}
User类,mm()的返回值就是Company类的hh()返回值
package com.one.util;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class User {
private Company company;
private int age;
public String mm(){
return company.hh();
}
}
然后UserTest类如下,此时下面的类ComapanyZi就相当于上面的被@Mock注解的company的最终被new的对象,只不过@Mock注解帮我做了下面的CompanyZi这个类,此时可以看到下面的ComapanyZi返回的是null
package com.one.util;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import static org.assertj.core.api.Assertions.catchThrowable;
@RunWith(JUnit4.class)
public class UserTest {
class ComapanyZi extends Company{
public ComapanyZi(String name) {
super(name);
}
public String hh(){
return null;
}
}
private User user;
@Test
public void name() {
user=new User(new ComapanyZi("zi"),1);
Throwable throwable = catchThrowable(() -> {
System.out.println(user.mm());
});
}
}
就是给@Mock注解的类添加一个final,然后在运行的时候就报错了
Company类,此时可以看到Compan已经被final修改了
package com.one.util;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public final class Company {
private String name;
public String hh(){
return "字符串";
}
}
User类
package com.one.util;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class User {
private Company company;
private int age;
public String mm(){
return company.hh();
}
}
然后测试如下,然后运行下面的name方法,然后结果如下所示
package com.one.util;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class UserTest {
@Mock
private Company company;
private User user;
@Before
public void setUp(){
user = new User(company,1);
}
@Test
public void name() {
user.mm();
}
}