Как ввести поля с помощью Mockito, не указывая их в конструкторе? - PullRequest
1 голос
/ 10 июня 2019

У меня есть класс (PriceSetter), который я тестирую с помощью Mockito, и у класса есть внутренняя зависимость (база данных). Я хочу смоделировать эту внутреннюю зависимость, а затем внедрить ее в класс, но эта зависимость не указана в моем конструкторе. Таким образом, Mockito автоматически пытается внедрить конструктор, и зависимость никогда не вводится.

Я пытался использовать @Mock для моего объекта базы данных и @InjectMocks для моего класса PriceSetter, но 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 вводятся через конструктор.

Ответы [ 2 ]

3 голосов
/ 10 июня 2019

@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;
    }

}
0 голосов
/ 12 июня 2019

тест пройден для меня так:

 @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");

...