Java 在JUnit/Mockito测试中注入bean返回零
我有一个带有无状态EJB的JavaEE应用程序,用于业务逻辑(Java 在JUnit/Mockito测试中注入bean返回零,java,junit,mockito,ejb,Java,Junit,Mockito,Ejb,我有一个带有无状态EJB的JavaEE应用程序,用于业务逻辑(EjbBusiness)和数据库访问(EjbDAO)。我需要在EjbBusiness上运行一个单元测试,但是DAO方法总是返回零 在下面的例子中,我有两个类和单元测试。我模拟连接到数据库的EjbDAO方法,以返回测试SQL连接: @Stateless public class EjbDAO { public Connection getConnFromPool() { Connection conn = n
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的一种方法,所以我在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)
返回零而不是5。另外,两个bean中的System.out.println
也不会打印。如何声明/模拟bean以使测试工作?仅在调用实际方法时使用@InjectMocks
,否则不要使用它。也不要同时使用@InjectMocks
和Mockito.mock()或@mock
在您的代码中,您在dao
对象上使用@injectmock
,并且您也为此创建了mock。当您希望存根方法调用而不是调用实际方法时,请使用Mockito.mock()
System.out.println()
在代码中不起作用,因为您为对象biz
和dao
创建了模拟。当使用模拟对象调用时,实际方法(即add2()
因此将0
作为输出)未执行
有关何时使用@InjectMocks
的更多信息,请参阅
@RunWith(MockitoJUnitRunner.class)
公共类单元测试{
@注射模拟
私营电子商务;
@嘲弄
私家EjbDAO道;
@以前
公共作废设置(){
initMocks(this);
}
@试验
公共void testBean(){
//这将返回测试连接
Mockito.doReturn(null).when(dao.getConnFromPool();
Mockito.doCallRealMethod().when(dao.add2)(Mockito.anyInt());
int i=业务地址2(3);
资产(i)isEqualTo(5);
}
}
仅当调用实际方法时才使用@InjectMocks
,否则不要使用它。也不要同时使用@InjectMocks
和Mockito.mock()或@mock
在您的代码中,您在dao
对象上使用@injectmock
,并且您也为此创建了mock。当您希望存根方法调用而不是调用实际方法时,请使用Mockito.mock()
System.out.println()
在代码中不起作用,因为您为对象biz
和dao
创建了模拟。当使用模拟对象调用时,实际方法(即add2()
因此将0
作为输出)未执行
有关何时使用@InjectMocks
的更多信息,请参阅
@RunWith(MockitoJUnitRunner.class)
公共类单元测试{
@注射模拟
私营电子商务;
@嘲弄
私家EjbDAO道;
@以前
公共作废设置(){
initMocks(this);
}
@试验
公共void testBean(){
//这将返回测试连接
Mockito.doReturn(null).when(dao.getConnFromPool();
Mockito.doCallRealMethod().when(dao.add2)(Mockito.anyInt());
int i=业务地址2(3);
资产(i)isEqualTo(5);
}
}
您不应该使用一个单元测试来测试两个类。
您应该有两个测试类来测试它们
比如说,
@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
设置为私有,因此该方法也应包含在测试中。如果您需要将其设置为私有或公共,则应由您进行选择。如果您决定将其公开,那么应该使用@Spy onEjbDAO
并模拟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);
}
}
希望有帮助。您不应该使用一个单元测试来测试两个类。 您应该有两个测试类来测试它们 比如说,
@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
设置为私有,因此该方法也应包含在测试中。如果您需要将其设置为私有或公共,则应由您进行选择。如果您决定将其公开,那么应该使用@Spy onEjbDAO
并模拟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);
}
}
希望能有所帮助。这是可行的,但是这种方法的问题是,如果dao对象中只有一个方法需要模拟,并且有10个方法需要运行real方法,那么我需要为每个real方法声明
Mockito.doCallRealMethod()
。有没有相反的方法?例如,要声明整个类和只需模拟一个方法。@ps0604您能否给出一个示例这是可行的,但是这种方法的问题是,如果dao对象中只有一个要模拟的方法,并且有10个方法需要运行实方法,那么我需要为每个实方法声明Mockito.doCallRealMethod()
。有没有相反的方法?例如,声明整个类和