英文:
The @Autowired field is null during tests with Junit, how can i mock/instantiate it?
问题
我无法访问 `MyClass2` 的代码,也无法更改它。我该如何对 `MyClass2 myClass2` 进行模拟/实例化?
类和代码测试:
@RunWith(JUnit4.class)//无法更改此部分
public class MyTest
{
@Autowired // 或者不使用,两种方式都尝试过
MyClass testedInstance = new MyClass();
@Test
public void boot() throws Exception{
testedInstance.boot();
assertTrue(true);
}
}
public class MyClass
{
@Autowired
private MyClass2 myClass2;
void boot()
{
myClass2.foo();//在这里得到空指针异常
}
}
英文:
I Have no access to MyClass2
code and can't change it. How do i mock/instantiate MyClass2 myClass2
?
Classes and code test:
@RunWith(JUnit4.class)//can't change thisone
public class MyTest
{
@Autowired // or not, tried both ways
MyClass testedInstance= new MyClass();
@Test
public void boot() throws Exception{
testedInstance.boot();
assertTrue(true);
}
}
public class MyClass
{
@Autowired
private MyClass2 myClass2;
void boot()
{
myClass2.foo();//getting a null pointer here
}
}
答案1
得分: 1
以下是翻译好的部分:
你可以查看原始回答:
https://stackoverflow.com/a/71591567/5108695
但这是一个非常常见的问题,所以我也在这里发布了答案。
在我看来,我们正在编写单元测试用例,我们不应该初始化 Spring 上下文来测试一段代码。
所以,
我使用 Mockito 来模拟我的主要目标测试类中的 Autowired
beans,并将这些模拟的 beans 注入到我的主要测试类对象中。
可能听起来有点混乱,看下面的示例 👇
我使用的依赖项:
testImplementation("org.mockito:mockito-core:2.28.2")
testImplementation("org.mockito:mockito-inline:2.13.0")
testImplementation("org.junit.jupiter:junit-jupiter:5.8.2")
testImplementation("org.mockito:mockito-junit-jupiter:4.0.0")
我的主类是 Maths
,并且自动装配了 Calculator
bean。
class Maths {
@Autowired Calculator cal;
// .........
// .........
public void randomAddMethod() {
cal.addTwoNumbers(1, 2); // 将返回 3;
}
}
测试类:
@ExtendWith(MockitoExtension.class)
class MathsTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS) Calculator cal;
@InjectMocks Maths maths = new Maths();
@Test
void testMethodToCheckCalObjectIsNotNull() {
maths.randomAddMethod();
}
}
现在,在 Maths
类中,cal
将不会为 null,并且将按预期工作。
英文:
you can check the original answer
https://stackoverflow.com/a/71591567/5108695
But this is very common problem so I posted the answer here also
In my opinion, we are writing unit test cases and we should not initialize the spring context in order to test a piece of code.
So,
I used Mockito to mock the Autowired
beans in my main target test class and injected those mock beans in my main test class Object
maybe sounds confusing, see the following example 💥
Dependencies I used
testImplementation("org.mockito:mockito-core:2.28.2")
testImplementation("org.mockito:mockito-inline:2.13.0")
testImplementation("org.junit.jupiter:junit-jupiter:5.8.2")
testImplementation("org.mockito:mockito-junit-jupiter:4.0.0")
My main class is Maths and Calculator bean is autowired
class Maths{
@Autowired Calculator cal;
.........
.........
public void randomAddMethod(){
cal.addTwoNumbers(1,2); // will return 3;
}
}
Test class
@ExtendWith(MockitoExtension.class)
class MathsTest{
@Mock(answer = Answers.RETURNS_DEEP_STUBS) Calculator cal;
@InjectMocks Maths maths = new Maths();
@Test testMethodToCheckCalObjectIsNotNull(){
maths.randomAddMethod();
}
}
Now cal
will not be null in Maths class and will work as expected
答案2
得分: 0
首先,您需要使用以下方式为测试类添加注解:
@RunWith(SpringJUnit4ClassRunner.class)
然后关于 MyClass:
@Autowired
MyClass testedInstance;
您需要删除 = new MyClass();
,因为您正在进行自动装配。
然后,由于现在您正在注入 MyClass
,如果存在可以注入的 MyClass2
实例,它将被注入到 MyClass
中,如果没有,就不会注入。
您需要配置应用程序上下下文,以便存在名为 MyClass2
的这样的 Bean。
英文:
First you need to annotate your test class with:
@RunWith( SpringJUnit4ClassRunner.class )
Then about MyClass:
@Autowired
MyClass testedInstance;
you need to delete the = new MyClass();
because you are autowiring it.
Then since now you are injecting MyClass
if there is available for injection instance of MyClass2 it will be injected in MyClass, if not it will not.
You need to configure your application context so that such bean MyClass2 exists,
答案3
得分: 0
如果您在测试中使用实现类作为自动装配的目的,但操作代码使用接口,并且存在代理,那么可能会出现问题。例如,如果您在使用Spring Security的@PreAuthorize
注解或者Spring AOP的切入点。我不能百分之百确定这是否会发生在CGLIB代理中,但绝对会在JDK代理中发生。
您必须获得确切正确的bean,否则事情将无法正常工作,由于正在测试的bean处于半配置状态,您将会收到非常奇怪(“不可能的”)空指针异常。
英文:
Something that can bite is if you're using the implementation class for autowiring purposes in tests, but the operational code is using an interface instead and there is proxying. This can happen if, for example, you are using @PreAuthorize
annotations from Spring Security, or pointcuts from Spring AOP. I'm not 100% sure if this happens with CGLIB proxies, but it definitely happens with JDK proxies.
You have to get exactly the correct bean or things will not work and you will get very strange ("impossible") null pointer exceptions due to the bean you're testing being in a half-configured state.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论