在 JUnit/Mockito 测试 returns 零中注入 bean
Injecting beans in a JUnit/Mockito test returns zero
我有一个带有无状态 EJB 的 JavaEE 应用程序,用于业务逻辑 (EjbBusiness
) 和数据库访问 (EjbDAO
)。我需要 运行 对 EjbBusiness
进行单元测试,但 DAO 方法总是 return 为零。
在下面的示例中,我同时进行了 类 和单元测试。我模拟连接到数据库的 EjbDAO
方法,return 测试 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的一个方法,所以我在UnitTest
:
中用@Spy注解了它
@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)
return 是零而不是 5。此外,两个 bean 中的 System.out.println
都没有打印出来。如何 declare/mock 用于测试的 bean 起作用?
仅在调用实际方法时使用@InjectMocks
,否则不要使用它。也不要一起使用 @InjectMocks
和 Mockito.mock() or @Mock
。
在您的代码中,您在 dao
对象上使用 @InjectMocks
,并且您还为此创建了 mock。当您想存根方法调用而不是调用实际方法时,请使用 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);
}
}
您不应使用一个单元测试来测试两个 class。
你应该有两个测试 classes 来测试它们。
例如,
@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);
}
}
在上面的 class 中,我们只测试方法 EjbBusinessTest.add2
并且我们不关心会发生什么或者方法 EjbDAO.add2
是否正常工作。在这方面,我们应该关心的是被测方法是否正常工作,因此我们模拟该方法外部的所有内容。
对 EjbDAO.add2
也采用类似的方法,测试用例应如下所示。我还将方法 EjbDAO.getConnection
设为私有,这样它也应该包含在测试中。如果您需要将其设为私有或 public,则应由您做出此选择。如果你决定保留它 public 那么你应该在 EjbDAO
上使用 @Spy 并模拟 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);
}
}
希望对您有所帮助。
我有一个带有无状态 EJB 的 JavaEE 应用程序,用于业务逻辑 (EjbBusiness
) 和数据库访问 (EjbDAO
)。我需要 运行 对 EjbBusiness
进行单元测试,但 DAO 方法总是 return 为零。
在下面的示例中,我同时进行了 类 和单元测试。我模拟连接到数据库的 EjbDAO
方法,return 测试 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的一个方法,所以我在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)
return 是零而不是 5。此外,两个 bean 中的 System.out.println
都没有打印出来。如何 declare/mock 用于测试的 bean 起作用?
仅在调用实际方法时使用@InjectMocks
,否则不要使用它。也不要一起使用 @InjectMocks
和 Mockito.mock() or @Mock
。
在您的代码中,您在 dao
对象上使用 @InjectMocks
,并且您还为此创建了 mock。当您想存根方法调用而不是调用实际方法时,请使用 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);
}
}
您不应使用一个单元测试来测试两个 class。 你应该有两个测试 classes 来测试它们。
例如,
@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);
}
}
在上面的 class 中,我们只测试方法 EjbBusinessTest.add2
并且我们不关心会发生什么或者方法 EjbDAO.add2
是否正常工作。在这方面,我们应该关心的是被测方法是否正常工作,因此我们模拟该方法外部的所有内容。
对 EjbDAO.add2
也采用类似的方法,测试用例应如下所示。我还将方法 EjbDAO.getConnection
设为私有,这样它也应该包含在测试中。如果您需要将其设为私有或 public,则应由您做出此选择。如果你决定保留它 public 那么你应该在 EjbDAO
上使用 @Spy 并模拟 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);
}
}
希望对您有所帮助。