Mockito:将真实对象注入私有的@Autowired字段

use*_*693 170 java spring mockito

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

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

    @InjectMocks
    private Demo demo;

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

public class Demo {

    @Autowired
    private SomeService service;

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

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

Dev*_*ked 263

使用@Spy注释

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

    @InjectMocks
    private Demo demo;

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

Mockito会将所有具有@Mock@Spy注释的字段视为注入注释的实例中的潜在候选项@InjectMocks.在上面的例子中,'RealServiceImpl'实例将被注入'demo'

有关详细信息,请参阅

的Mockito回家

@间谍

@嘲笑

  • +1:为我工作......除了String对象.Mockito抱怨​​说:"Mockito不能模仿/间谍跟随: - 最后的类 - 匿名类 - 原始类型` (8认同)
  • 顺便说一句,没有必要`new RealServiceImpl()`,`@Spy private SomeService服务;`无论如何都要使用默认构造函数创建一个真实的对象. (7认同)
  • 就我而言,Mockito **不** 注入间谍。不过它确实注入了一个 Mock。该字段是私有的,没有 setter。 (3认同)
  • @AdrianPronk String 是最后一个类 (2认同)

Yoa*_*nda 17

除了@Dev Blanked的答案,如果你想使用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);
    }

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

这样您就不需要更改代码(添加另一个构造函数)来使测试工作.

  • @Aada你能详细说明吗? (2认同)
  • 我已经尝试过了。但我从设置方法收到空指针异常 (2认同)

tak*_*sot 15

Spring 有一个专门的实用程序用于ReflectionTestUtils此目的。采取具体实例并注入到现场。


@Spy
..
@Mock
..

@InjectMock
Foo foo;

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


dav*_*xxx 10

Mockito 不是一个 DI 框架,甚至 DI 框架也鼓励构造函数注入而不是字段注入。
因此,您只需声明一个构造函数来设置被测试类的依赖关系:

@Mock
private SomeService serviceMock;

private Demo demo;

/* ... */
@BeforeEach
public void beforeEach(){
   demo = new Demo(serviceMock);
}
Run Code Online (Sandbox Code Playgroud)

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

创建真实对象的间谍。间谍会调用真正的方法,除非它们被存根。真正的间谍应该偶尔谨慎使用,例如在处理遗留代码时。

像往常一样,您将阅读partial mock warning:面向对象编程通过将复杂性划分为单独的、特定的 SRPy 对象来解决复杂性。部分模拟如何适应这种范式?好吧,它只是不...部分模拟通常意味着复杂性已转移到同一对象上的不同方法。在大多数情况下,这不是您想要的应用程序设计方式。

然而,在极少数情况下,部分模拟会派上用场:处理无法轻松更改的代码(第三方接口、遗留代码的临时重构等)。但是,我不会将部分模拟用于新的、测试驱动的和良好的-设计的代码。