如何使用 Mockito 注入字段而不在构造函数中指定它们



我有一个类(PriceSetter(,我正在使用Mockito进行测试,并且该类具有内部依赖项(数据库(。我想模拟这个内部依赖项,然后将其注入类中,但在我的构造函数中没有指定依赖项。因此,Mockito自动尝试进行构造函数注入,并且永远不会注入依赖项。

我尝试在我的数据库对象上使用@Mock,在我的PriceSetter类上使用@InjectMocks,但Mockito自动调用构造函数,并且由于数据库未传递到构造函数中,因此无法注入我的数据库模拟。

class PriceSetter {
    private Table priceTable;
    public PriceSetter(Dependency d1, Dependency d2) {
        this.d1 = d1;
        this.d2 = d2;
    }
}
@RunWith(MockitoJUnitRunner.class)
class PriceSetterTest{
    @InjectMocks
    private PriceSetter setter;
    @Mock Table priceTable;
    @Mock Dependency d1;
    @Mock Dependency d2;
    @Test
    public void someTestMethod() {
        when(priceTable.getItem(any())).thenReturn(Specified item);
        setter.priceTable.getItem("item"); -> Doesn't return item specified by mocked behavior
    }
}

我希望priceTable被注射,但它没有注射。只有 d1 和 d2 是通过构造函数注入的

@InjectMocks只会执行构造函数注入或属性注入中的一个,而不是两者。

Mockito将尝试通过构造函数注入来注入模拟, 二传手注入,还是属性注入顺序...

你总是可以做的

@Before
public void setUp() {
   setter.setPriceTable(priceTable);
}

或者,您的桌子应该连线。 但是,最干净的设计通常是统一依赖项注入方法,将所有内容注入构造函数。 由于@InjectMocks将选择最大的构造函数并在私有或包私有构造函数上工作,因此一种选择是添加构造函数重载:

class PriceSetter {
    private Table priceTable;
    public PriceSetter(Dependency d1, Dependency d2) {
        this(d1, d2, new DefaultPriceTable());
    }
    PriceSetter(Dependency d1, Dependency d2, Table priceTable) {
        this.d1 = d1;
        this.d2 = d2;
        this.priceTable = priceTable;
    }
}

测试像这样通过了:

 @RunWith(MockitoJUnitRunner.class)
public class PriceSetterTest{
    public PriceSetterTest() {}
    @InjectMocks
    private PriceSetter priceSetter;
    @Mock
    Table priceTable;
    @Mock
    Dependency1 d1;
    @Mock Dependency1 d2;
    @Test
    public void someTestMethod() {
        when(priceTable.getItem(any())).thenReturn("aa" );
        Assert.assertEquals("aa",priceTable.getItem("item"));
    }
}

你应该添加一个默认的构造函数(没有参数(和做priceTable.getItem("item") setter.priceTable.getItem("item");

如果您使用旧的 Mockito 版本,那么快速但肮脏的方法是使用 org.mockito.internal.util.reflection.Whitebox.setInternalState 来修改测试对象的内部状态(它在构造函数调用后使用反射来修改字段(。

@Test
public void someTestMethod() {
    when(priceTable.getItem(any())).thenReturn("MOCKED!");
    Whitebox.setInternalState(setter, "priceTable", priceTable);
    Assert.assertEquals("MOCKED!",  setter.priceTable.getItem("item"));
}

这种方法的缺点是"内部"Mockito软件包,并且功能隐藏在较新版本中。顺便说一句,在这种情况下有几种解决方法;)。

相关内容

  • 没有找到相关文章

最新更新