英文:
Unable to mock with Quarkus, NullPointer exception and cannot find relevant imports
问题
我正在尝试使用Mockito为Quarkus编写单元测试,但是在模拟方面遇到了问题。
这是一个最小(不)工作示例:
package com.my.package;
import io.quarkus.test.junit.QuarkusTest;
import org.mockito.Mockito;
import org.mockito.Mock;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@QuarkusTest
public class LoadCalculatorServiceTest {
public class Foobar {
public int baz;
public void setBaz(int baz) {
this.baz = baz;
}
public int getBaz() {
return this.baz;
}
}
@Mock
Foobar foobar;
// Foobar foobar = new Foobar(); // 也不起作用
@Test
public void myTest() {
Mockito.when(foobar.getBaz()).thenReturn(4); // 空指针异常
Assertions.assertEquals(4, foobar.getBaz());
}
}
测试在空指针异常上崩溃。
我阅读到这种问题可以通过在测试上加注解@RunWith(MockitoJUnitRunner.class)
、@ExtendWith(MockitoExtension.class)
来解决(出于某种原因,我本来以为@QuarkusTest
会自动处理?),但是我无法找到正确的导入方式加载它们。
我尝试过org.junit.jupiter.api.MockitoExtension
、org.junit.runner.RunWith
等各种变体,但都没有成功。
这是我pom.xml
的相关部分:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-mockito</artifactId>
<scope>test</scope>
</dependency>
我错过了什么?
英文:
I am trying to write unit tests for Quarkus using Mockito, but I fail mocking things.
Here is a minimal (not) working example :
package com.my.package;
import io.quarkus.test.junit.QuarkusTest;
import org.mockito.Mockito;
import org.mockito.Mock;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@QuarkusTest
public class LoadCalculatorServiceTest {
public class Foobar {
public int baz;
public void setBaz(int baz) {
this.baz = baz;
}
public int getBaz() {
return this.baz;
}
}
@Mock
Foobar foobar;
// Foobar foobar = new Foobar(); // doesn’t work either
@Test
public void myTest() {
Mockito.when(foobar.getBaz()).thenReturn(4); // NullPointer
Assertions.assertEquals(4,foobar.getBaz());
}
}
The test crashes on a NullPointer.
I read such issues may be fixed by annotating the test with @RunWith(MockitoJUnitRunner.class)
, @ExtendWith(MockitoExtension.class)
(which for some reason I expected @QuarkusTest
to do anyway ?), however I fail to find the correct imports to load them.
I tried org.junit.jupiter.api.MockitoExtension
, org.junit.runner.RunWith
and variations, without success.
Here is the relevant part of my pom.xml
:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-mockito</artifactId>
<scope>test</scope>
</dependency>
What am I missing ?
答案1
得分: 6
我发现原始代码使用普通样式的模拟工作:
Foobar foobar = Mockito.mock(Foobar.class);
所以实际的问题是如何使@Mock
注解起作用?为此需要几个步骤:
-
@RunWith
注解已经被JUnit5中的@ExtendWith
注解替代(或者我们可以说是升级)。在Quarkus中,可以使用import org.junit.jupiter.api.extension.ExtendWith;
导入。 -
@RunWith
通常被用作@ExtendWith(MockitoExtension.class)
。可以通过import org.mockito.junit.jupiter.MockitoExtension;
在Quarkus中导入MockitoExtension。注意,必须将mockito-junit-jupiter
依赖(来自org.mockito
组)添加到pom.xml
中,因为quarkus-junit5-mockito
包不依赖于它。 -
必须在测试之前通过
MockitoAnnotations.initMocks()
初始化模拟。请注意,尽管使用@BeforeAll
作为设置函数似乎更合理,但显然这不是此注解的用途,应该使用@BeforeEach
(前者需要设置为静态,并且据我所知,设置函数将在每个测试之前调用)。 -
最后,
@Mock
注解应该起作用。
总之,原始代码将变为:
package com.my.package;
import io.quarkus.test.junit.QuarkusTest;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
@QuarkusTest
@ExtendWith(MockitoExtension.class)
public class LoadCalculatorServiceTest {
public class Foobar {
public int baz;
public void setBaz(int baz) {
this.baz = baz;
}
public int getBaz() {
return this.baz;
}
}
@BeforeEach
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Mock
Foobar foobar;
@Test
public void myTest() {
Mockito.when(foobar.getBaz()).thenReturn(4);
Assertions.assertEquals(4,foobar.getBaz());
}
}
并且需要将以下内容添加到pom.xml
中:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
英文:
I figured the original code works with plain-style mocks :
Foobar foobar = Mockito.mock(Foobar.class);
So the question is actually how to make the @Mock
annotation work ? There are several things needed for that :
-
The
@RunWith
annotation has been replaced (or should we say upgraded) by@ExtendWith
in JUnit5. It can be imported in Quarkus usingimport org.junit.jupiter.api.extension.ExtendWith;
. -
@RunWith
is usually used as@ExtendWith(MockitoExtension.class)
. MockitoExtension can be imported in Quarkus usingimport org.mockito.junit.jupiter.MockitoExtension;
. Beware that themockito-junit-jupiter
dependency (from theorg.mockito
group) must be added to thepom.xml
, since thequarkus-junit5-mockito
packages do not depend on it. -
Mocks have to be initialized by
MockitoAnnotations.initMocks()
before the tests. Note that although it may seem to make more sense to use@BeforeAll
for the setup function, apparently it is not the point of this annotation and one should use@BeforeEach
(the former needs the setup to be static, and IIUC the setup function will be called before each test anyway). -
Then finally the
@Mock
annotation should work.
To summarize, the original code would become :
package com.my.package;
import io.quarkus.test.junit.QuarkusTest;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
@QuarkusTest
@ExtendWith(MockitoExtension.class)
public class LoadCalculatorServiceTest {
public class Foobar {
public int baz;
public void setBaz(int baz) {
this.baz = baz;
}
public int getBaz() {
return this.baz;
}
}
@BeforeEach
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Mock
Foobar foobar;
@Test
public void myTest() {
Mockito.when(foobar.getBaz()).thenReturn(4);
Assertions.assertEquals(4,foobar.getBaz());
}
}
with the following addition to the pom.xml
:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
答案2
得分: 0
我正在使用Quarkus 1.8.1.Final,以及Mockito 3.6.0。我在使用@Mock注解时遇到了相同的问题,然后我按照Skippy le Grand Gourou的回答进行了操作,但没有成功。因此,我删除了@QuarkusTest注解,并且删除了MockitoAnnotations.initMocks(this)方法。我的Mockito版本已经弃用了这个方法,然后测试使用@Mock注解运行起来了。我刚开始使用Quarkus,所以我不太清楚移除@QuarkusTest注解会有什么副作用。
英文:
I'm using quarkus 1.8.1.Final, with mockito 3.6.0, I had the same issue with @Mock annotation and I followed the answer from Skippy le Grand Gourou and it didn't work, so I deleted the @QuarkusTest annotation, and delete de MockitoAnnotations.initMocks(this) method, my mockito version has deprecated this, then the test run with the @Mock annotation. I'm new doing Quarkus so I don't know very well the side effects of removing @QuarkusTest
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论