【问题标题】:JUnit + Spring: Dependency Injection when testing fails - CannotLoadBeanClassExceptionJUnit + Spring:测试失败时的依赖注入 - CannotLoadBeanClassException
【发布时间】:2018-12-10 15:23:06
【问题描述】:

我目前遇到的问题是,在使用 JUnit 进行单元测试时,无法找到通过 ClassPathXmlApplicationContext 注入的依赖项。 为了测试整个事情,我正在运行 Maven 测试。 正常运行应用程序时,一切正常,每个依赖项都得到解决。一旦使用这种类型的依赖注入,问题就会开始出现。

不使用这种类型的依赖注入的其他软件模块的单元测试也可以正常工作。在我的例子中,一个模块是一个 maven 项目(没有 maven 模块),它引用了其他较低级别的 maven 项目。 (例如,一个 maven 项目包含逻辑和另一个,包含第一个引用的应用程序的所有相关数据库模型等)

为了更容易解决问题,我在一个规模小得多的项目上重新创建了它,我现在将对其进行描述。

我的小规模架构由三个模块(Maven 项目)组成:

  • 包含将被注入的类的模块(用户)
  • 经过测试并引发异常的模块。 (junittest)
  • 包含将要注入的类的接口的模块。其他两个模块都在各自的 pom.xml 中引用了这个。

需要注意的是,第二个模块“junittest”在 pom.xml 中没有“user”作为直接依赖项。这需要保持这种状态以防止循环依赖。

现在是相关的类和xml文件:

模块“junittest” - 要测试的类

每当 junit 测试调用 useExternalInjectedDependency() 方法时,就会抛出异常(您可以在我的帖子后面看到)。

public class ToBeTested {
    private final String CONTEXT_FILENAME = "tobetestedContext.xml";

    private final String USERMANAGER_BEAN_ID = "userManager";

    private IUserManager userManager;

    public void useExternalInjectedDependency() {
        if (this.userManager == null) {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(CONTEXT_FILENAME);
            this.userManager = context.getBean(USERMANAGER_BEAN_ID, IUserManager.class);
            context.close();
        }
    }
}

模块“junittest” - 依赖注入的上下文文件

<?xml version="1.0" encoding="UTF-8"?>
...
<!-- GET USERMANAGER BY DEPENDENCY INJECTION -->
<bean id="userManager" class="com.project.modules.user.UserManager">
</bean>

模块“junittest” - pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>test.test</groupId>
    <artifactId>junittest</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <main.basedir>${basedir}/../..</main.basedir>
        <maven.compiler.source>9</maven.compiler.source>
        <maven.compiler.target>9</maven.compiler.target>
        <java.version>9</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.project.modules</groupId>
            <artifactId>defaultmodels</artifactId>
            <version>[0.0.1-SNAPSHOT,)</version>
        </dependency>

        <!-- Spring dependencies -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.0.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.0.3.RELEASE</version>
        </dependency>

        <!-- Dependencies for testing -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!-- Include Maven Surefire for Unit testing -->
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.0</version>
                    <configuration>
                        <argLine>-Djdk.attach.allowAttachSelf</argLine>
                        <includes>
                            <include>**/*Test.java</include>
                        </includes>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

我遇到的错误

[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running junittest.ToBeTestedTest
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.938 s <<< FAILURE! - in junittest.ToBeTestedTest
[ERROR] testDependencyInjectionViaContext(junittest.ToBeTestedTest)  Time elapsed: 0.87 s  <<< ERROR!
org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [com.project.modules.user.UserManager] for bean with name 'userManager' defined in class path resource [tobetestedContext.xml]; nested exception is java.lang.ClassNotFoundException: com.project.modules.user.UserManager
    at junittest.ToBeTestedTest.testDependencyInjectionViaContext(ToBeTestedTest.java:10)
Caused by: java.lang.ClassNotFoundException: com.project.modules.user.UserManager
    at junittest.ToBeTestedTest.testDependencyInjectionViaContext(ToBeTestedTest.java:10)

我能做些什么来解决这个问题并解决依赖关系吗?如果需要,我很乐意提供有关问题和我的应用程序的更多信息。


更新

所以我找到了解决问题的方法。虽然不是很干净,但它现在确实有效。对于任何有兴趣的人: 我基本上为无法正确注入的接口创建了虚拟实现,并将它们放在 src/test/java 中。除了接口所需的实现方法之外,它们不包含真正的源代码,它们实现了。 我还创建了一个新的 context.xml,其中包含现在本地实现(虚拟实现)的路径,并将其放在 src/test/resources 文件夹中。

【问题讨论】:

    标签: java spring maven junit dependency-injection


    【解决方案1】:

    试试这个:

    ApplicationContext context = new ClassPathXmlApplicationContext(CONTEXT_FILENAME);
    

    ApplicationContext context = new ClassPathXmlApplicationContext("file:src/main/resources/beans.xml");
    

    file:指向文件系统资源的前缀,而不是类路径。

    【讨论】:

    • 感谢您的快速答复!我刚刚尝试了您的解决方案,但遗憾的是仍然遇到同样的错误。出于进一步测试的目的,我将通常会从另一个模块注入的 IUserManager 实现直接放入“junittest”模块中,以查看注入是否可以从那里工作。结果是它确实有效,但仅适用于您提供的解决方案(第二个)。如果我尝试用我的旧方法注入它,它就不起作用。也许这些信息可以为我们提供一些解决这个问题的新提示。
    • 请检查 buildpath 中添加的 src/main/java 目录?
    • 刚刚检查过,是的,src/main/java 目录在构建路径中。所以我昨天找到了解决我问题的方法。这不是最干净的解决方案,但它确实有效。如果您感兴趣,请查看我在上面更新的帖子中所做的事情。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-16
    • 1970-01-01
    • 2017-02-10
    • 1970-01-01
    • 2014-10-27
    相关资源
    最近更新 更多