我使用Mockito的@Mock和@InjectMocks注释将依赖注入到Spring的@Autowired注释的私有字段中:

@RunWith(MockitoJUnitRunner.class)
public class DemoTest {
    @Mock
    private SomeService service;

    @InjectMocks
    private Demo demo;

    /* ... */
}

and

public class Demo {

    @Autowired
    private SomeService service;

    /* ... */
}

现在我还想将真实对象注入私有的@Autowired字段(没有setter)。这是可能的还是该机制仅限于注入mock ?


当前回答

除了@Dev blank之外,如果你想使用Spring创建的现有bean,代码可以修改为:

@RunWith(MockitoJUnitRunner.class)
public class DemoTest {

    @Inject
    private ApplicationContext ctx;

    @Spy
    private SomeService service;

    @InjectMocks
    private Demo demo;

    @Before
    public void setUp(){
        service = ctx.getBean(SomeService.class);
    }

    /* ... */
}

通过这种方式,您不需要更改代码(添加另一个构造函数)就可以使测试正常工作。

其他回答

使用@Spy注释

@RunWith(MockitoJUnitRunner.class)
public class DemoTest {
    @Spy
    private SomeService service = new RealServiceImpl();

    @InjectMocks
    private Demo demo;

    /* ... */
}

Mockito将考虑所有具有@Mock或@Spy注释的字段作为潜在的候选者注入到带有@InjectMocks注释的实例中。在上面的例子中'RealServiceImpl'实例将被注入到'demo'中

详情请参考

Mockito-home

@Spy

@Mock

我知道这是一个老问题,但我们在尝试注入string时也面临同样的问题。因此,我们发明了一个JUnit5/Mockito扩展,它完全可以满足您的需求:https://github.com/exabrial/mockito-object-injection

编辑:

@InjectionMap
 private Map<String, Object> injectionMap = new HashMap<>();

 @BeforeEach
 public void beforeEach() throws Exception {
  injectionMap.put("securityEnabled", Boolean.TRUE);
 }

 @AfterEach
 public void afterEach() throws Exception {
  injectionMap.clear();
 }

除了@Dev blank之外,如果你想使用Spring创建的现有bean,代码可以修改为:

@RunWith(MockitoJUnitRunner.class)
public class DemoTest {

    @Inject
    private ApplicationContext ctx;

    @Spy
    private SomeService service;

    @InjectMocks
    private Demo demo;

    @Before
    public void setUp(){
        service = ctx.getBean(SomeService.class);
    }

    /* ... */
}

通过这种方式,您不需要更改代码(添加另一个构造函数)就可以使测试正常工作。

在Spring中,有一个名为ReflectionTestUtils的专用实用程序用于此目的。获取特定的实例并注入到字段中。


@Spy
..
@Mock
..

@InjectMock
Foo foo;

@BeforeEach
void _before(){
   ReflectionTestUtils.setField(foo,"bar", new BarImpl());// `bar` is private field
}

Mockito不是依赖注入框架,即使是依赖注入框架也鼓励构造函数注入而不是字段注入。 所以你只需要声明一个构造函数来设置被测类的依赖关系:

@Mock
private SomeService serviceMock;

private Demo demo;

/* ... */
@BeforeEach
public void beforeEach(){
   demo = new Demo(serviceMock);
}

在一般情况下使用Mockito间谍是一个糟糕的建议。它使测试类变得脆弱,而不是直接且容易出错:真正被嘲笑的是什么?真正测试的是什么? @InjectMocks和@Spy也损害了整体设计,因为它鼓励了臃肿的类和类中的混合责任。 请在盲目使用spy() javadoc之前阅读它(我不是强调):

Creates a spy of the real object. The spy calls real methods unless they are stubbed. Real spies should be used carefully and occasionally, for example when dealing with legacy code. As usual you are going to read the partial mock warning: Object oriented programming tackles complexity by dividing the complexity into separate, specific, SRPy objects. How does partial mock fit into this paradigm? Well, it just doesn't... Partial mock usually means that the complexity has been moved to a different method on the same object. In most cases, this is not the way you want to design your application. However, there are rare cases when partial mocks come handy: dealing with code you cannot change easily (3rd party interfaces, interim refactoring of legacy code etc.) However, I wouldn't use partial mocks for new, test-driven & well-designed code.