繁体   English   中英

如何使用jmockit对Singleton模式进行单元测试

[英]how to do unit test for Singleton pattern using jmockit

有一个java类,它基于Singleton模式。 如何为这门课进行单元测试? 以下是我的相关代码:

public class ConfigFromFile implements ConfigStrategy {
  private String endpoint;
  private final static String CONFIG_FILE = "/conf/config.properties";

  private InputStream getInputStream(String configFilePath) throws FileNotFoundException{
    return new FileInputStream(configFilePath);
  }

  private void initFromFile() {
    Properties prop = new Properties();
    InputStream input = null;
    try {
      input = getInputStream(CONFIG_FILE);
      prop.load(input);
      endpoint = prop.getProperty("endpoint");
    } catch(Exception e) {
      e.printStackTrace();
    } finally {
      if (input != null) {
        try {
          input.close();
        } catch (IOException e) {
        }
      }
    }
  }

  private ConfigFromFile() {
    initFromFile();
  }

  private static class ConfigFromFileHolder {
    private static ConfigFromFile instance = new ConfigFromFile();
  }

  public static ConfigFromFile getInstance() {
    return ConfigFromFileHolder.instance;
  }

  @Override
  public String getEndpoint() {
      return endpoint;
  }
}

我需要为这门课写单元测试。

  • 单元测试无法调用外部资源,因此我们需要模拟调用“/conf/config.properties”文件。 我们可以使用jmockit。
  • 这个类基于Singleton模式。 我们希望这两种情况之间的相互作用不会受到影响。

以下是我的情况:

  1. Case1,这是正常情况,文件内容是“endpoint = www.baidu.com”
  2. Case2,这是一个异常情况,我们可以模拟这个文件不存在。

如何实施这些案例? 谢谢!

您可以添加一个包范围构造函数,该构造函数接收要加载的文件的路径 ,并让您的测试在临时文件夹中创建一个假文件,然后创建一个测试实例,并传入该文件的路径。 不需要嘲笑。

public class ConfigFromFile implements ConfigStrategy {
  private static final String CONFIG_FILE = "/conf/config.properties";
  private final String configFilePath;
  private String endpoint;

  // Visible for testing
  ConfigStrategy(String configFilePath) {
    this.configFilePath = configFilePath;
  }

  private ConfigStrategy() {
    this(CONFIG_FILE);
  }

  private void initFromFile() {
    try (InputStream input = new FileInputStream(configFilePath)) {
      Properties prop = new Properties();
      prop.load(input);
      endpoint = prop.getProperty("endpoint");
    } catch(Exception e) {
      e.printStackTrace();
    }
  }

  ...

}

注意我重写了initFromFile()使用try-with-resources ,如果您使用的是JDK 7或更高版本,则可以执行此操作。

您可能想重新考虑此类是否需要是静态单例。 它不仅使代码难以测试,而且无法配置为在不同环境中使用不同的文件。 请记住, 类的测试是类的第一个API用户 如果您的测试难以编写,则表明您的API存在问题。

如果你需要限制一个实例,我建议使用像Guice或Spring这样的依赖注入框架 如果您使用Spring,您的类可以实现InitializingBean并在构造类之后但在将其注入另一个类之前加载配置文件:

public class ConfigFromFile implements ConfigStrategy, InitializingBean {
  private final String configFilePath;
  private String endpoint;

  ConfigStrategy(String configFilePath) {
    this.configFilePath = configFilePath;
  }

  @Override
  public void afterPropertiesSet() throws IOException {
    try (InputStream input = new FileInputStream(configFilePath)) {
      Properties prop = new Properties();
      prop.load(input);
      endpoint = prop.getProperty("endpoint");
    }
  }

  @Override
  public String getEndpoint() {
    return endpoint;
  }
}

是的,这就是您需要的所有代码。

  • 无需捕捉异常
  • 加载配置文件的异常不会被忽略
  • 无需getEndpoint()检查初始化是否失败

你可以用Guice做类似的事情

但是等等,如果你使用Spring,并且你愿意将端点值移动到Spring配置中,那么它会变得更简单!

public class ConfigFromSpring implements ConfigStrategy {
  private final String endpoint;

  ConfigStrategy(String endpoint) {
    this.endpoint = endpoint;
  }

  @Override
  public String getEndpoint() {
    return endpoint;
  }
}

这个类很简单,不需要任何单元测试。

你的bean XML看起来像这样:

<bean id="config" class="examples.ConfigFromSpring">
  <constructor-arg type="String" value="end of the road"/>
</bean>

当然,在这一点上,我将摆脱ConfigStrategy并在使用配置的对象上设置配置。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM