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

我正在用TestNG测试一个商业服务,在弹簧启动应用程序中进行模拟单元测试。

应用是多模块弹簧启动项目。我正在为业务模块编写单元测试。

我在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{}

我的测试应用看起来像

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

如果我不使用 , 这些注释,那么我在测试中的模拟 DAO 调用工作正常。@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Inherited

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

例如,如果我想执行一个使用多个业务服务的单个任务,那么它们不会在一个事务中发生。换句话说,如果业务呼叫使用多个业务服务,则说和 。呼叫从 到 。如果 中发生异常,则通过 wont 回滚完成数据库更改。ServiceAServiceBserviceAserviceBserviceBserviceA

当我使用上面的注释时,上面的示例有效,但是在 junit 测试中模拟 DAO 调用不起作用。

我在 pom 中有错误的依赖关系吗?

  1. 为什么这不起作用?
  2. 解决方案是什么?

Git Repository 源代码 ,在这里您将获得示例代码。它在编译时给了我一些错误。


答案 1

我建议你保持测试的简单性。您可以从DI收益中获利。有关更多详细信息,请访问春季文档

依赖关系注入的一个主要优点是,它应该使代码更易于单元测试。您可以使用新的运算符简单地实例化对象,甚至无需涉及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;
}

答案 2

你可以尝试使用MockitoJUnitRunner吗?

@RunWith(MockitoJUnitRunner.class)
@ContextConfiguration(classes = { TestApp.class })
class MyTestClass{ 
..
}

推荐