java - 注释服务以使用@Retention、@Transactional、@Inherited 进行测试后,TestNG 单元测试不起作用

标签 java unit-testing spring-boot testng mockito

我正在使用 TestNG 测试业务服务,在 Spring Boot 应用程序中进行模拟单元测试。

应用程序是多模块spring boot项目。我正在为业务模块编写单元测试。

我在pom中添加了以下依赖相关的测试,

<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>

我的包装注释看起来像

@Service
@Transactional
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyServiceAnnotation{}

我的 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;
       }
}

MyTestClass 看起来像

@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)@Inherited这些注解然后我在测试中的模拟 DAO 调用工作正常。

我需要上面的注释,因为如果我不使用它们,那么,

例如,如果我想执行一个使用多个业务服务的单个任务,那么 它们不会发生在一个事务中。 换句话说,如果一个业务调用使用多个业务服务,例如 ServiceAServiceB。调用从 serviceA 转到 serviceB。如果 serviceB 发生异常,则 serviceA 所做的数据库更改不会回滚。

当我使用上面的注释时,上面的例子可以工作,但是在 junit 测试中模拟 DAO 调用不起作用。

我在 pom 中是否有错误的依赖项?

  1. 为什么这不起作用?
  2. 解决办法是什么?

Git Repository Source Code ,在这里你会得到示例代码。它在编译时给了我一些错误。

最佳答案

我建议您保持测试简单。您可以从 DI yield 中获利。更多详情请访问Spring documentation :

One of the major advantages of dependency injection is that it should make your code easier to unit test. You can simply instantiate objects using the new operator without even involving Spring. You can also use mock objects instead of real dependencies.

您的测试类应该如下所示。

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

关于java - 注释服务以使用@Retention、@Transactional、@Inherited 进行测试后,TestNG 单元测试不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31315433/

相关文章:

java - 解压缩/提取 Spring Tools Suite 下载的 Zip/Jar 文件时出错

android - Mockito lenient() 何时使用

java - SpringBoot Thymeleaf 无法解析模板

spring - 结合 springBoot 和 elasticsearch 2.x

Java spring-rest/Jersey 如何使用过滤器保护休息路线

java - JSP 错误 : According to TLD, 标记形式 :input must be empty, 但不是

java - 谷歌日历 Activity , session 详情未设置

java - 更新所有项目的 gradle

objective-c - 如何使用kiwi测试函数调用的参数?

c# - 生命周期范围由 IoC 容器处理的单元测试对象