Инъекция бобов в тесте JUnit / Mockito возвращает ноль - PullRequest
0 голосов
/ 11 апреля 2020

У меня есть приложение JavaEE с EJB без сохранения состояния, которое я использую для бизнес-логики c (EjbBusiness) и доступа к базе данных (EjbDAO). Мне нужно запустить модульный тест на EjbBusiness, но метод DAO всегда возвращает ноль.

В приведенном ниже примере у меня есть оба класса и модульный тест. Я высмеиваю метод EjbDAO, который подключается к базе данных, чтобы вернуть тестовое соединение SQL:

@Stateless
public class EjbDAO {


    public Connection getConnFromPool() {
        Connection conn = null; // in production this would return a connection
        return conn;
    }


    public int add2(int i) {
        Connection conn = getConnFromPool();
        System.out.println("in EjbDAO: " + i);
        return i + 2;
    }

}


@Stateless
public class EjbBusiness {


    @Inject
    private EjbDAO dao;


    public int add2(int i) {
         int j = dao.add2(i);
         System.out.println("in EjbBusiness: " + j);
         return j;

    }

}

Поскольку я высмеиваю один из методов EjbDAO, я аннотирую его @Spy в UnitTest:

@RunWith(MockitoJUnitRunner.class)
public class UnitTest {

    @InjectMocks
    private EjbBusiness biz;

    @InjectMocks
    @Spy
    private EjbDAO dao;

    @Before
    public void setup() {
        dao = Mockito.mock(EjbDAO.class);
        biz = Mockito.mock(EjbBusiness.class);
        MockitoAnnotations.initMocks(this);
    }


    @Test
    public void testBean() {

        // this would return the testing connection
        Mockito.doReturn(null).when(dao).getConnFromPool();

        int i = biz.add2(3);

        assertThat(5).isEqualTo(i);
    }
}

Проблема в том, что утверждение не работает, так как biz.add2(3) возвращает ноль вместо 5. Кроме того, System.out.println в обоих bean-компонентах не печатается. Как объявить / смоделировать бины для теста на работу?

Ответы [ 2 ]

1 голос
/ 16 апреля 2020

Вы не должны использовать один модульный тест для проверки обоих классов. У вас должно быть два тестовых класса для их проверки.

Например,

@RunWith(MockitoJUnitRunner.class)
public class EjbBusinessTest {

    @InjectMocks
    private EjbBusiness biz;

    @Mock
    private EjbDAO dao;


    @Test
    public void testAdd2() {

        // this would return the testing connection
        Mockito.doReturn(null).when(dao).getConnFromPool();
        Mockito.doReturn(5).when(dao).add2();

        int i = biz.add2(3);

        assertThat(5).isEqualTo(i);
    }
}

В вышеприведенном классе мы тестируем только метод EjbBusinessTest.add2, и нам все равно, что происходит или если метод EjbDAO.add2 работает правильно. При этом все, что нас должно волновать, - работает ли тестируемый метод должным образом, поэтому мы высмеиваем все, что является внешним по отношению к этому методу.

Следуя аналогичному подходу и для EjbDAO.add2, тестовый пример должен выглядеть примерно так, как показано ниже. Я также сделал метод EjbDAO.getConnection закрытым, чтобы его также включали в тест. Этот выбор должен быть сделан вами, если вам нужно сделать его приватным или публичным c. Если вы решите сохранить его в открытом доступе c, тогда вам следует использовать @Spy для EjbDAO и высмеивать метод EjbDAO.getConnection.


@RunWith(MockitoJUnitRunner.class)
public class EjbDAOTest {

    //instantiate this object the way you want. Mock the external objects used inside this like the library used to get connection inside EjbDAO.getConnection() Method  
    @InjectMocks
    private EjbDAO dao;


    @Test
    public void testAdd2() {

        // I would suggest you to make the getConnection method private.
        // do not mock the getConnection here, instead mock how you are getting the connection inside the  getConnection method. 
        int i = dao.add2(3);

        assertThat(5).isEqualTo(i);
    }
}

Надеюсь, это поможет.

1 голос
/ 15 апреля 2020

Используйте @InjectMocks только тогда, когда вы вызываете реальный метод, иначе не используйте его. И также не используйте @InjectMocks и Mockito.mock() or @Mock вместе.

В своем коде вы используете @InjectMocks на dao объекте, и вы также создаете для этого насмешливый образ. И используйте Mockito.mock(), когда вы хотите заблокировать вызовы методов вместо вызова реальных методов.

System.out.println() не работает в вашем коде, потому что вы создали насмешки для объектов biz и dao. Фактические методы (т. Е. add2(), из-за этого вы получаете 0 в качестве вывода), не выполняются при вызове с фиктивными объектами.

Для получения дополнительной информации о том, когда использовать @InjectMocks, обратитесь к this

@RunWith(MockitoJUnitRunner.class)
public class UnitTest {

    @InjectMocks
    private EjbBusiness biz;

    @Mock
    private EjbDAO dao;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }


    @Test
    public void testBean() {

        // this would return the testing connection
        Mockito.doReturn(null).when(dao).getConnFromPool();
        Mockito.doCallRealMethod().when(dao).add2(Mockito.anyInt());

        int i = biz.add2(3);

        assertThat(i).isEqualTo(5);
    }
}
...