Spring Mockito @injectmocks无法正常工作

时间:2017-01-11 06:50:04

标签: java spring unit-testing mockito

您好我正在使用Mockito来测试我的Spring项目,但@InjectMocks似乎无法将模拟服务注入另一个Spring服务(bean)。

这是我要测试的Spring服务:

@Service
public class CreateMailboxService {   
    @Autowired UserInfoService mUserInfoService; // this should be mocked
    @Autowired LogicService mLogicService;  // this should be autowired by Spring

    public void createMailbox() {
        // do mething
        System.out.println("test 2: " + mUserInfoService.getData());
    }

}

以下是我想要模拟的服务:

@Service
public class UserInfoService {
    public String getData() {
        return "original text";
    }
}

我的测试代码在这里:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring/root-context.xml" })
public class CreateMailboxServiceMockTest {

    @Mock
    UserInfoService mUserInfoService;

    @InjectMocks
    @Autowired
    CreateMailboxService mCreateMailboxService;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void deleteWithPermission() {
        when(mUserInfoService.getData()).thenReturn("mocked text");

        System.out.println("test 1: " + mUserInfoService.getData());

        mCreateMailboxService.createMailbox();
    }
}

但结果是

test 1: mocked text
test 2: original text  // I want this be "mocked text", too

似乎 CreateMailboxService 没有获得模拟的 UserInfoService ,而是使用Spring的自动连接bean。 为什么我的@InjectMocks无效?

此致

8 个答案:

答案 0 :(得分:3)

您可以在package课程中为mUserInfoService创建CreateMailboxService关卡设置器。

@Service
public class CreateMailboxService {   
    @Autowired UserInfoService mUserInfoService; // this should be mocked
    @Autowired LogicService mLogicService;  // this should be autowired by Spring

    public void createMailbox() {
        // do mething
        System.out.println("test 2: " + mUserInfoService.getData());
    }

    void setUserInfoService(UserInfoService mUserInfoService) {
        this.mUserInfoService = mUserInfoService;
    }
}

然后,您可以使用setter在测试中注入该模拟。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring/root-context.xml" })
public class CreateMailboxServiceMockTest {

    @Mock
    UserInfoService mUserInfoService;

    CreateMailboxService mCreateMailboxService;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        mCreateMailboxService = new CreateMailboxService();
        mCreateMailboxService.setUserInfoService(mUserInfoService);
    }

    ...
}

这样可以避免@InjectMocks和Spring注释的问题。

答案 1 :(得分:2)

如果您尝试使用@Mock注释进行直接依赖于Spring注入的测试,则可能需要将 @Mock 替换为 @MockBean @Inject (这两个注释),以及 @InjectMocks @Inject 。以您的示例为例:

@MockBean
@Inject
UserInfoService mUserInfoService;

@Inject
CreateMailboxService mCreateMailboxService;

答案 2 :(得分:2)

我也有类似的情况。我把它写下来,以防万一任何读者都经历同样的事情。就我而言,我发现问题在于我在本地类中将注入的变量设置为final

按照您的示例,我遇到了这样的事情:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring/root-context.xml" })
public class CreateMailboxServiceMockTest {

    @Mock
    UserInfoService mUserInfoService;

    @InjectMocks
    CreateMailboxService mCreateMailboxService = new CreateMailboxService(mUserInfoService);

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void deleteWithPermission() {
        ...
    }
}

但是在这堂课上我是这样的:

@Service
public class CreateMailboxService {   

    private final UserInfoService mUserInfoService; // it is NOT injecting Mocks just because it is final! (all ok with private)


    private final LogicService mLogicService;  // it is NOT injecting Mocks just because it is final! (all ok with private)

    @Autowired
    public CreateMailboxService(UserInfoService mUserInfoService, LogicService mLogicService) {
        this.mUserInfoService = mUserInfoService;
        this.mLogicService = mLogicService;
    }

    public void createMailbox() {
        ...
    }

}

只需删除final条件,即可解决@InjectMocks问题。

答案 3 :(得分:2)

就我而言,我在使用 JUnit5 时遇到了类似的问题

val STATUT_ID_OK : List[String] = List("103","104","613")
val STATUT_ID_KO : List[String] = List("106","546","609","17")
val STATUT_ID_KO_AND_OK: List[String] = STATUT_ID_OK  ::: STATUT_ID_KO

val df = Seq(("100"), ("101"), ("102"), ("103")).toDF("mycol")

df.where(col("mycol").isin(STATUT_ID_KO_AND_OK: _*)).show(false)

// returns
+-----+
|mycol|
+-----+
|103  |
+-----+

@ExtendWith(MockitoExtension.class) class MyServiceTest { ... @InjectMocks MyService underTest; @Test void myMethodTest() { ... } 为空。 问题的原因是我使用了 JUnit4 包 underTest 中的 @Test 而不是 JUnit5 import org.junit.Test;

答案 4 :(得分:1)

对于那些偶然发现此线程并与JUnit 5一起运行的用户,您需要更换 @RunWith(SpringJUnit4ClassRunner.class)

@ExtendWith(MockitoExtension.class) @RunWith(JUnitPlatform.class)

在此处进一步阅读https://www.baeldung.com/mockito-junit-5-extension。不幸的是,在使用旧注释的junit 5中执行测试用例时,没有任何提示。

答案 5 :(得分:1)

对于使用 JUnit 5 运行的用户,您需要将@RunWith(SpringJUnit4ClassRunner.class)替换为@ExtendWith(MockitoExtension.class)

要进一步阅读,请看here

答案 6 :(得分:0)

在注入测试类时不需要@Autowired注释。并使用模拟方法获取您的模拟响应,就像您为UserInfoService所做的那样。这将是下面的内容。 Mockito.when(mCreateMailboxService。getData())。thenReturn(“my response”);

答案 7 :(得分:0)

您可以使用 MockitoJUnitRunner 在单元测试中进行模拟。 在要模拟其行为的类上使用 @Mock 注释。 在您正在测试的类上使用 @InjectMocks。 使用新的和初始化的类(最好进行依赖注入)或为您的注入引入 setter 是一种不好的做法。使用 setter 注入仅为测试设置依赖项是错误的,因为不应为测试更改生产代码。

@RunWith(MockitoJUnitRunner.class)
public class CreateMailboxServiceMockTest {

    @Mock
    UserInfoService mUserInfoService;

    @InjectMocks
    CreateMailboxService mCreateMailboxService;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    ...
}