Java 将服务注释为使用@Retention、@Transactional、@Inherited进行测试后,TestNG单元测试不起作用
我正在spring boot应用程序中使用TestNG、mockito单元测试测试业务服务 应用程序是多模块spring boot项目。我正在为业务模块编写单元测试 我在pom中添加了以下与依赖项相关的测试Java 将服务注释为使用@Retention、@Transactional、@Inherited进行测试后,TestNG单元测试不起作用,java,unit-testing,spring-boot,testng,mockito,Java,Unit Testing,Spring Boot,Testng,Mockito,我正在spring boot应用程序中使用TestNG、mockito单元测试测试业务服务 应用程序是多模块spring boot项目。我正在为业务模块编写单元测试 我在pom中添加了以下与依赖项相关的测试 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
<version>${javaxel.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.servlet</artifactId>
<version>${javax.servlet.version}</version>
<scope>test</scope>
</dependency>
我的TestApp看起来像
@SpringBootApplication
public class TestApp{ .... }
@MyServiceAnnotation
public class AddressServiceImpl implements AddressService {
@Autowire
UserDAO userDAO;
@Autowire
AddressDAO addressDAO;
public Address find(int userId) {
user = userDAO.findOne(userId);
/** if I run following test then I get user NULL.
But it should get user object which I have created
in data provider
**/
if(user == null ) { throw new BadReqExcp("invalid user Id", 101); }
address = user.findAddresses();
if(address is empty) { throw new BadReqExcp("add not found", 102);}
return address;
}
}
@ContextConfiguration(classes = { TestApp.class })
class MyTestClass{
@Mock
UserDAO userDAO;
@InjectMocks
@Autowire
AddressService addressServie;
@BeforeMethod
public void initMock() {
MockitoAnnotations.initMocks(this);
}
@Test(dataProvider = "getUser", dataProviderclass = UserDP.class)
public void shouldThrowExceptionAddressNotFound(int userId, User user)
{
when(userDAO.findOne(userId)).thenReturn(user); //here dao call should return user but it is returning null
try{
addressService.find(userId);
}
catch(BadReqExcp e){
// Here errro code should be 102 but fount 101
assertEquals(e.getErrorCode(), 102);
}
}
}
我的商务服务看起来像
@SpringBootApplication
public class TestApp{ .... }
@MyServiceAnnotation
public class AddressServiceImpl implements AddressService {
@Autowire
UserDAO userDAO;
@Autowire
AddressDAO addressDAO;
public Address find(int userId) {
user = userDAO.findOne(userId);
/** if I run following test then I get user NULL.
But it should get user object which I have created
in data provider
**/
if(user == null ) { throw new BadReqExcp("invalid user Id", 101); }
address = user.findAddresses();
if(address is empty) { throw new BadReqExcp("add not found", 102);}
return address;
}
}
@ContextConfiguration(classes = { TestApp.class })
class MyTestClass{
@Mock
UserDAO userDAO;
@InjectMocks
@Autowire
AddressService addressServie;
@BeforeMethod
public void initMock() {
MockitoAnnotations.initMocks(this);
}
@Test(dataProvider = "getUser", dataProviderclass = UserDP.class)
public void shouldThrowExceptionAddressNotFound(int userId, User user)
{
when(userDAO.findOne(userId)).thenReturn(user); //here dao call should return user but it is returning null
try{
addressService.find(userId);
}
catch(BadReqExcp e){
// Here errro code should be 102 but fount 101
assertEquals(e.getErrorCode(), 102);
}
}
}
MyTestClass看起来像
@SpringBootApplication
public class TestApp{ .... }
@MyServiceAnnotation
public class AddressServiceImpl implements AddressService {
@Autowire
UserDAO userDAO;
@Autowire
AddressDAO addressDAO;
public Address find(int userId) {
user = userDAO.findOne(userId);
/** if I run following test then I get user NULL.
But it should get user object which I have created
in data provider
**/
if(user == null ) { throw new BadReqExcp("invalid user Id", 101); }
address = user.findAddresses();
if(address is empty) { throw new BadReqExcp("add not found", 102);}
return address;
}
}
@ContextConfiguration(classes = { TestApp.class })
class MyTestClass{
@Mock
UserDAO userDAO;
@InjectMocks
@Autowire
AddressService addressServie;
@BeforeMethod
public void initMock() {
MockitoAnnotations.initMocks(this);
}
@Test(dataProvider = "getUser", dataProviderclass = UserDP.class)
public void shouldThrowExceptionAddressNotFound(int userId, User user)
{
when(userDAO.findOne(userId)).thenReturn(user); //here dao call should return user but it is returning null
try{
addressService.find(userId);
}
catch(BadReqExcp e){
// Here errro code should be 102 but fount 101
assertEquals(e.getErrorCode(), 102);
}
}
}
如果我不使用@Target(ElementType.TYPE)
,@Retention(RetentionPolicy.RUNTIME)
,@继承的
这些注释,那么我的模拟DAO调用在测试中可以正常工作
我需要上面的注释,因为如果我不使用它们
例如,如果我想执行使用多个业务服务的单个任务,那么它们不会在一个事务中发生。
换句话说,如果一个业务呼叫使用多个业务服务,比如ServiceA
和ServiceB
。呼叫从serviceA
转到serviceB
。如果serviceB
中发生异常,则serviceA
所做的数据库更改不会回滚
当我使用上述注释时,上述示例可以工作,但junit测试中的模拟DAO调用不起作用。
pom中是否存在错误的依赖项
,这里您将获得示例代码。它在编译时给了我一些错误 我认为这个问题可能是由于注释处理顺序造成的 您可能可以尝试在before方法中显式设置服务的内部状态,如下所示:
@Mock
UserDAO userDAO;
@Autowire
AddressService addressServie;
@BeforeMethod
public void initMock() {
MockitoAnnotations.initMocks(this);
// using mockito Whitebox
org.mockito.internal.util.reflection.Whitebox.setInternalState(addressServie, "userDAO", userDAO);
/* or using spring test method
org.springframework.test.util.ReflectionTestUtils.setField(addressServie, "userDAO", userDAO);*/
}
并检查错误是否仍然发生删除所有注释。你需要一些特殊的东西才能使交易顺利进行 问题: 呼叫从服务A转到服务B。如果在中发生异常 serviceB则serviceA所做的数据库更改不会回滚 Spring的事务管理器提供了一个独立于技术的API,允许您启动 通过调用getTransaction()方法并通过 提交()
回滚() As PlatformTransactionManager是 交易管理 您为事务管理调用的方法是有保证的 独立于技术
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
public class TransactionalJdbcBookShop extends JdbcDaoSupport implements BookShop {
@Autowired
private PlatformTransactionManager transactionManager;
然后在dao方法中,您可以配置提交和回滚方法
public void purchase(String isbn, String username) {
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
//Your query over here
transactionManager.commit(status);
} catch (DataAccessException e) {
//if the above query fails then
transactionManager.rollback(status);
throw e;
}
}
transactionmanager在XML配置文件中声明为普通bean
为了
例如
下面的bean配置声明了一个DataSourceTransactionManager实例
它要求设置dataSource属性,以便它可以管理ConnectionsMake的事务
通过这个数据源
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="bookShop"
class="com.apress.springrecipes.bookshop.TransactionalJdbcBookShop">
<property name="dataSource" ref="dataSource" />
<property name="transactionManager" ref="transactionManager" />
</bean>
您还可以通过github在应用程序中实现bean
一旦有了事务定义
通过调用getTransaction()方法,可以要求事务管理器使用该定义启动新事务
那么它会的
返回TransactionStatus对象以跟踪事务状态
如果所有的声明
如果执行成功,则要求事务管理器通过传递
处于事务状态
因为SpringJDBC模板引发的所有异常都是子类
对于DataAccessException,您要求transactionmanager在捕获此类异常时回滚事务
在这个类中,您已经声明了常规类型的事务管理器属性
平台TransactionManager
现在您必须插入一个适当的事务管理器
实施
由于您只处理单个数据源并使用JDBC访问它,
您应该选择数据源TransactionManager是否可以尝试使用
我建议你保持测试简单。您可以从DI福利中获利。详情请浏览: 依赖项注入的一个主要优点是它应该使代码更容易进行单元测试。您可以使用new操作符简单地实例化对象,甚至不涉及Spring。您还可以使用模拟对象而不是真实的依赖项 您的测试类应该是这样的
public class AddressTest {
@Mock
private UserDAO userDAO;
@Mock
private AddressDAO addressDAO;
@InjectMocks
private AddressService addressServie;
@BeforeMethod
public void initMock() {
addressServie = new AddressServiceImpl();
MockitoAnnotations.initMocks(this);
}
@Test(dataProvider = "getUser", dataProviderClass = UserDP.class)
public void shouldThrowExceptionAddressNotFound(int userId, User user) {
when(userDAO.findOne(userId)).thenReturn(user);
try {
addressServie.findAllAddress(userId);
} catch (BadRequestException badRequestException) {
assertEquals(badRequestException.getErrorCode(), 102);
}
}
}
您还应该在实现中检查空地址列表。测试失败,因为提供程序类为测试提供了未初始化地址列表的用户实例
@Override
public List<Address> findAllAddress(int userId) {
User user = userDAO.findOne(userId);
if (user == null) {
throw new BadRequestException("Invalid user id", 101);
}
List<Address> addresses = user.getAddresses();
if (addresses == null || addresses.isEmpty()) {
throw new BadRequestException("Address Not found", 102);
}
return addresses;
}
@覆盖
公共列表findAllAddress(int userId){
User=userDAO.findOne(userId);
if(user==null){
抛出新的BadRequestException(“无效用户id”,101);
}
列表地址=user.getAddresses();
if(addresses==null | | addresses.isEmpty()){
抛出新的BadRequestException(“未找到地址”,102);
}
返回地址;
}
您在哪里使用@MyService
?用于所有我的业务服务,例如@MyService class AddressService{}。请查看更新的问题。您遇到了什么异常?没有,但您在服务中看到了。如果Usernotfound,我抛出自己的异常Usernotfound,因此断言失败,但是userDAO方法运行正常吗?我的意思是你得到了一个usernotfound异常,但这意味着你的DAO运行良好,也许只是用户真的不存在?因为首先我认为您的userdaobean不存在,但这是另一个问题,它说的是“运行时无法设置内部状态”。正如使用SpringBootApplication进行测试一样。虽然我只需要一个上下文,但这是一个问题。我如何只使用一个上下文而不使用SpringBoot应用程序。有一件事,如果@Target(ElementType.TYPE)、@Retention(RetentionPolicy.RUNTIME)、@Inheritated未使用,它们为什么会工作。测试会去掉所有这些,只测试类方法。因为一个类的实例被初始化,Mockito注入了伪de