Spring Mockito @injectmocks无法正常工作

Vic*_*sai 6 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());
    }

}
Run Code Online (Sandbox Code Playgroud)

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

@Service
public class UserInfoService {
    public String getData() {
        return "original text";
    }
}
Run Code Online (Sandbox Code Playgroud)

我的测试代码在这里:

@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();
    }
}
Run Code Online (Sandbox Code Playgroud)

但结果会如此

test 1: mocked text
test 2: original text  // I want this be "mocked text", too
Run Code Online (Sandbox Code Playgroud)

似乎CreateMailboxService 没有得到模拟的UserInfoService,而是使用Spring的自动装配bean.为什么我@InjectMocks不工作?

问候

Ole*_*kov 18

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

@ExtendWith(MockitoExtension.class)
class MyServiceTest {
...

@InjectMocks
MyService underTest;

@Test
void myMethodTest() {
...
}
Run Code Online (Sandbox Code Playgroud)

underTest为空。问题的原因是我使用了@TestJUnit4 包import org.junit.Test;而不是 JUnit5import org.junit.jupiter.api.Test;


小智 9

对于那些偶然发现此线程并使用 JUnit 5 运行的人,您需要替换 @RunWith(SpringJUnit4ClassRunner.class)

@ExtendWith(MockitoExtension.class)
@RunWith(JUnitPlatform.class)
Run Code Online (Sandbox Code Playgroud)

在这里进一步阅读。不幸的是,在使用旧注释通过 JUnit 5 执行测试用例时没有提示。


小智 8

我有一个非常相似的情况。我把它写下来,以防万一读者也有同样的经历。就我而言,我发现问题在于我将注入的变量设置为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() {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

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

@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() {
        ...
    }

}
Run Code Online (Sandbox Code Playgroud)

只要删除final条件,@InjectMocks问题就解决了。


ala*_*yor 6

您可以在课堂上创建package水平设置器。mUserInfoServiceCreateMailboxService

@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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用 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);
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以避免@InjectMocksSpring 注释的问题。


小智 6

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

@MockBean
@Inject
UserInfoService mUserInfoService;

@Inject
CreateMailboxService mCreateMailboxService;
Run Code Online (Sandbox Code Playgroud)