51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

查看: 476|回复: 0
打印 上一主题 下一主题

[转贴] Javaer 如何做单元测试?(一)

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2022-8-2 14:36:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
前言:
  本文适用于 javaer,其他开发者或许可以借鉴。
  写本文的主旨有两个,一是简单的给大家介绍下单元测试,二是通过一个简单的示例来介绍一些单元测试的技巧,希望以此来降低大家写单元测试的门槛。
  1、单元测试的定义
  单元测试通常是由软件开发人员编写和运营的自动化测试,以确保应用程序的一部分(称为“单元”符合其设计并按预期运行。在编程过程中,一个单元可以是一个完整的模块,但更常见的是一个单独的函数或过程。在面向对象编程中,一个单元通常是一个完整的接口,例如一个类,或者一个单独的方法。通过首先为最小的可测试单元编写测试,然后是它们之间的复合行为,可以为复杂的应用程序构建全面的测试。
  简单来说,单元测试是针对一个单元编写测试方法。其中的单元可以是一个很单纯的函数,也可以是一个完整的接口,该接口中可以包含各种其他函数的调用。
  2、单元测试用例
  该项目的 SpringBoot 版本是 2.2.5.RELEASE。
<parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starters</artifactId>
      <version>2.2.5.RELEASE</version>
  </parent>
 2-1.项目文件准备
  假设有项目文件的目录结构如下:



其中依赖关系为:
java-study-web-provider 依赖 java-study-web-api, java-study-common-provider
  java-study-web-api 依赖 java-study-common-api
  java-study-common-provider 依赖 java-study-web-api, java-study-common-api
在 java-study-web-api 包中有个rpc 包,其中有两个 rpc 接口,分别是  WebRpc.class & WebRpc2.class。然而,这两个接口的实现类在 java-study-web-provider 包中。






 public interface WebRpc {
      ApiResult<String> get();
      ApiResult<String> get2(String param);
  }
public interface WebRpc2 {
      ApiResult<String> get();
      ApiResult<String> get(String param);
  }
 @Service
  public class WebRpcImpl implements WebRpc {
      @Override
      public ApiResult<String> get() {
          return ApiResult.success("get success");
      }
      @Override
      public ApiResult<String> get2(String param) {
          return ApiResult.success(param);
      }
  }
 @Service
  public class WebRpc2Impl implements WebRpc2 {
      @Override
      public ApiResult<String> get() {
          return ApiResult.success("get success");
      }
      @Override
      public ApiResult<String> get(String param) {
          return null;
      }
  }

在 java-study-common-provider 包中有个 service 包,其中有两个 service 接口以及对应的实现类,分别是CommonEntityService.class,CommonEntityService2.class,CommonEntityServiceImpl.class, CommonEntityService2Impl.class,在两个实现类中都有引用 rpc 接口。


public interface CommonEntityService {
      ApiResult<Void> test(CommonEntity commonEntity);
  }
 public interface CommonEntityService2 {
  }
 @Service
  public class CommonEntityServiceImpl implements CommonEntityService {
      private final Logger logger = LoggerFactory.getLogger(this.getClass());
      @Autowired
      private CommonEntityManager commonEntityManager;
      @Autowired
      private WebRpc webRpc;
      @Override
      public ApiResult<Void> test(CommonEntity commonEntity) {
          // webRpc 单元测试时可能为null
          ApiResult<String> getRpc = webRpc.get();
          if (!getRpc.getSuccess()) {
              logger.info("getRpc fail: {}", getRpc);
              return ApiResult.error(getRpc);
          }
          ApiResult<String> getRpc2 = webRpc.get2("test");
          if (!getRpc2.getSuccess()) {
              logger.info("getRpc2 fail: {}", getRpc2);
              return ApiResult.error(getRpc2);
          }
          // 依赖远程方法调用结果
          Optional<String> remoteResultOpt = RmiUtil.getRemoteResult();
          if (!remoteResultOpt.isPresent()) {
              logger.info("getRemoteResult fail");
              return ApiResult.error(BizRespStatusEnum.SYS_ERR);
          }
          // 入库
          int insertNo = commonEntityManager.insert(commonEntity);
          logger.info("insert {} common entity", insertNo);
          return ApiResult.success(null);
      }
  }
@Service
  public class CommonEntityService2Impl implements CommonEntityService2 {
      @Autowired
      private WebRpc2 webRpc2;
  }
2-2.针对 CommonEntityService.class 编写单元测试
  先加入 SpringBootTest 依赖。
<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
          <exclusion>
              <groupId>org.junit.vintage</groupId>
              <artifactId>junit-vintage-engine</artifactId>
          </exclusion>
      </exclusions>
  </dependency>
创建对应的单元测试类。
@ExtendWith(SpringExtension.class)
  @SpringBootTest(classes = CommonTestApplication.class)
  public class CommonEntityServiceTest {
      private final Logger logger = LoggerFactory.getLogger(this.getClass());
      @Autowired
      private CommonEntityService commonEntityService;
      @Test
      public void test() {
          ApiResult<Void> testSuccess = commonEntityService.test(new CommonEntity());
          Assert.isTrue(testSuccess.getSuccess(), "testSuccess fail");
          logger.info("testSuccess: {}", JSON.toJSONString(testSuccess));
      }
  }
当我们去执行单元测试的 test() 方法时,会出现 NoSuchBeanDefinitionException 异常。
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.peng.java.study.web.api.rpc.WebRpc2' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1695)
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1253)
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207)
          at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)
          ... 43 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.peng.java.study.web.api.rpc.WebRpc2' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1695)
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1253)
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207)
          at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)
          ... 43 more
这是因为我们执行单元测试的这个模块虽然依赖了 java-study-web-api 包,能够调用 rpc 方法,但是没有依赖 java-study-web-provider 包,没办法注入对应的实现类。
  有三种方法可以解决这个问题:
  I .将该单元测试类挪到 java-study-web-provider 包中,这样就能加载到所有的 bean 了。
  这个方法有局限性,每次执行单元测试都需要加载所有模块的文件,大大的降低了单元测试的效率。
  II .在注入rpc的注解 @Autowired 上加上 required = false
@Autowired(required = false)
  private WebRpc2 webRpc2;
这个方法有局限性,假设每次新增的 service 类都需要注入同一个 rpc 时,那每个 rpc 的注解 @Autowired 都需要使用 required = false,不然就没办法启动单元测试,由此可见是比较麻烦的。























本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

x
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

本版积分规则

关闭

站长推荐上一条 /1 下一条

小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

GMT+8, 2024-4-28 17:51 , Processed in 0.071963 second(s), 24 queries .

Powered by Discuz! X3.2

© 2001-2024 Comsenz Inc.

快速回复 返回顶部 返回列表