测试代码依赖于类路径上的类的存在

时间:2015-01-25 15:42:42

标签: java unit-testing maven classpath

我有一个项目,如果SLF4J在类路径上,我需要提供SLF4J日志记录,否则直接提供日志记录到控制台。我使用类似于:

的代码实例化我的记录器
try {
    Class.forName("org.slf4j.LoggerFactory");
    return new Slf4JLogProvider();
} catch (ClassNotFoundException e) {
    System.out.println("SLF4J not on classpath, defaulting to console logging");
}
return new ConsoleLogProvider();

请注意Slf4JLogProvider是SLF4J的自定义包装器,它不属于SLF4J本身。

我的项目基于Maven,此模块声明了对SLF4J的可选依赖项:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <optional>true</optional>
</dependency>

我希望能够测试此代码。 Classpath很棘手,正确测试它是恕我直言的重要。基本上,我希望能够在测试期间修改类加载器以确保SLF4J不存在并验证控制台日志记录是否已初始化。

有没有&#34;清洁&#34;这样做的方式?任何可以为类路径依赖测试提供支持的框架?在特定的类加载器中隔离测试的任何标准方法?

正如@piotrek所指出的,这可能使这个集成测试不仅仅是一个单元测试。

2 个答案:

答案 0 :(得分:1)

您可以使用自定义类加载器执行此操作。 Class.forName()调用加载包含Class.forName()调用的类的类加载器。因此,当您的测试类尝试加载SLF4J时,它将调用加载被测试类的相同类加载器。您可以编写自定义类加载器并使用该加载器加载受测试类的副本。该类的副本将使用您的自定义类加载器来加载其他类,这使您有机会隐藏您不希望被测试的类访问的类。

您的自定义类加载器将子类化现有的类加载器类(ClassLoader或URLClassLoader)。你会添加这种行为:

  1. 当请求加载其中一个要隐藏的类时,加载程序会假装找不到该类。
  2. 当请求加载被测试的类时,直接从存储它的位置加载类。这将为您提供将使用此类加载器的类的副本。
  3. 将其他类(java.lang.String等)的请求传递给父类加载器。
  4. 使用此自定义类加载器加载受测试类的副本。生成的类对象和从类对象创建的实例将调用您的自定义加载程序来加载其他类。当被测试的类试图加载SLF4J时,您的自定义加载器将表现为该类不存在。

    编写代码示例有点牵扯,但这里有一些链接说明了如何编写自定义类加载器。

答案 1 :(得分:-1)

提取Class.forName("org.slf4j.LoggerFactory");以分隔服务并在测试中模拟它。你会发现一条线

其他方法是使用不同的类路径运行一些测试。不幸的是,在maven或gradle中没有很好的支持。但是使用蚂蚁/常春藤很容易做到

ps:如果不在课程路径上,您确定可以在班级中声明new Slf4JLogProvider();吗?是不是解析jvm依赖的类声明?