【问题标题】:Using JMockit and Spring AOP together一起使用 JMockit 和 Spring AOP
【发布时间】:2015-08-16 00:54:17
【问题描述】:

假设我有一个如下所示的程序:

@Component
public class MainAction {
    public void doTheAction() {
        System.out.println("Now doing the action");
    }
}

@Aspect
@Component
public class BeforeAspect {
    @Autowired
    private Logger logger;

    @Before("execution(* thepackagename.MainAction.*(..))")
    public void doBefore() {
        logger.log("The @Before advice has run");
    }
}

@Component
public class Logger {
    public void log(String s) {
        System.out.println(s);
    }
}

如果我通过 Eclipse 运行它就可以正常工作(主要方法在 mainAction 由 Spring 创建之后调用 mainAction.doTheAction())。

现在我想编写一个测试,确保在调用doTheAction 时正确调用log 方法。我们正在使用 JMockit 进行测试。 (这是我实际面临的问题的一个非常简化的案例;通过 AOP 方面调用了一个更复杂的记录器,并且正在记录错误的值。在修复之前,我正在尝试编写一个测试以确保记录的值正确。)

这是我的(简化的)测试目前的样子:

@RunWith(JMockit.class)
@ContextConfiguration(locations = {"classpath:Beans.xml"})
public class MainActionTest {
    @Tested
    private MainAction mainAction;

    @Test
    public void testThatLoggerIsCalled(@Injectable Logger logger) {
        new Expectations() { {
            logger.log(anyString);
        } };
        mainAction.doTheAction();
    }
}

@ContextConfiguration 可能没用。早些时候我尝试过@RunWith(SpringJunit4ClassRunner.class),这就是为什么@ContextConfiguration 在那里,但没有处理任何嘲笑的东西。另外,按照this question 中的建议,我使用@Tested@Injectable 而不是@Autowired@Mocked;没有它,mainAction 仍然为空。所以现在测试运行,Now doing the action 出现在输出中。但是The @Before advice has run没有出现(即使我不嘲笑Logger也没有出现),期望失败。

如何同时使用 JMockit 和 AOP?

编辑: 根据要求,我添加了一些东西来打印类路径属性。这是(删除了一些路径名的不重要部分):

Eclipse workspaces\springtest8\target\test-classes
Eclipse workspaces\springtest8\target\classes
C:\eclipse\plugins\org.junit_4.11.0.v201303080030\junit.jar
C:\eclipse\plugins\org.hamcrest.core_1.3.0.v201303031735.jar
.m2\repository\org\jmockit\jmockit\1.18\jmockit-1.18.jar
.m2\repository\junit\junit\4.11\junit-4.11.jar
.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar
.m2\repository\org\springframework\spring-context\4.2.0.RELEASE\spring-context-4.2.0.RELEASE.jar
.m2\repository\org\springframework\spring-aop\4.2.0.RELEASE\spring-aop-4.2.0.RELEASE.jar
.m2\repository\aopalliance\aopalliance\1.0\aopalliance-1.0.jar
.m2\repository\org\springframework\spring-beans\4.2.0.RELEASE\spring-beans-4.2.0.RELEASE.jar
.m2\repository\org\springframework\spring-core\4.2.0.RELEASE\spring-core-4.2.0.RELEASE.jar
.m2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar
.m2\repository\org\springframework\spring-expression\4.2.0.RELEASE\spring-expression-4.2.0.RELEASE.jar
.m2\repository\org\aspectj\aspectjrt\1.8.6\aspectjrt-1.8.6.jar
.m2\repository\org\aspectj\aspectjweaver\1.8.6\aspectjweaver-1.8.6.jar
.m2\repository\org\springframework\spring-test\4.2.0.RELEASE\spring-test-4.2.0.RELEASE.jar
.m2\repository\javax\inject\javax.inject\1\javax.inject-1.jar
/C:/eclipse/configuration/org.eclipse.osgi/bundles/201/1/.cp/
/C:/eclipse/configuration/org.eclipse.osgi/bundles/200/1/.cp/

编辑 2:我通过从配置构建路径的库选项卡中删除 JUnit4 来完成工作。

【问题讨论】:

    标签: java junit spring-aop jmockit


    【解决方案1】:

    以下测试工作正常,使用 Spring 3.0 或更高版本(使用 Spring 3.0.7、4.0.5 和 4.2.0 测试):

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:beans.xml")
    public class MainActionTest
    {
        @Inject MainAction mainAction;
    
        @Test
        public void testThatLoggerIsCalled(@Mocked final Logger logger)
        {
            mainAction.doTheAction();
    
            new Verifications() {{ logger.log(anyString); }};
        }
    }
    

    【讨论】:

    • 我仍然收到Method testThatLoggerIsCalled should have no parameters。我正在使用 Spring 4.1.0——也尝试过 4.2.0。此外,Eclipse 将我的 JUnit 设置为 3.8.1——我需要更高版本吗?您是使用来自javax.inject 的@Inject 还是其他地方?
    • 这个关于“没有参数”的错误也确实发生在我身上,但只有如果我使用基于旧 JUnit 4.4 测试运行器的 Spring 2.5。 JMockit Spring Test 4.1的最低JUnit版本是JUnit 4.5;它不能与 3.8.1 一起使用(但这可能是别的东西——运行时类路径中的 junit.jar 很可能是 JUnit 4.x)。
    • 我接受答案是为了让赏金不会过期。但我会继续努力确保版本正确,并会及时通知您。
    • 我正在使用 Eclipse。如果我查看配置构建路径,JUnit4 的条目是 C:\eclipse\plugins\org.junit_4.11.0.v201303080030。 JUnit 3.8.1 是一个 Maven 依赖项。我更新了 pom.xml 以使用 JUnit 4.11。我还尝试将 JUnit4 放在构建路径中 Maven 依赖项的前面和后面。我没有任何工作。
    • 通过将System.getProperty("java.class.path") 打印到控制台来检查您的实际运行时类路径。请注意,Eclipse 在构建路径中有 两个 jar 列表(我不知道为什么这样做,因为其他 IDE 有一个列表),并且它不会将命令行打印到控制台运行测试,这使得很难找到类路径问题。
    【解决方案2】:

    我从来不需要用 RunWith 注释 JUnit 测试来使用 JMockit。在documentation 中,您需要确保 jmockit jar 在 junit 之前加载或添加 javaagent jvm 参数。这样您就可以使用 Spring 的 Junit Runner 运行测试,并将 JMockit 作为模拟框架。

    【讨论】:

    • 是的,这应该可以。我只能补充说,被测类的实例化/注入需要由 Spring 完成,否则方面将不起作用。要模拟注入的Logger,测试必须使用@Capturing 而不是@Injectable
    • 这对我不起作用。我得到 Method testThatLoggerIsCalled should have no parameters(来自 SpringJUnit4ClassRunner.java 内部),如果我使用 @RunWith(JMockit.class),我不会得到。我正在使用 Maven 依赖项,我在 pom.xml 中将jmockit 移动到junit 上方(实际上,jmockit 现在是第一个)并清理并重建了项目。那么我还忘了做什么呢?
    • @Rogério 我仍然无法让它工作(见之前的评论)。
    • 现在我在想也许我可以在没有方法参数的情况下让它工作。 (明天会尝试。)(最初,当我收到错误时,我认为我不能使用SpringJUnit4ClassRunner,所以我放弃了这个想法。)但似乎有一些 JMockit 功能可以在没有@RunWith(JMockit.class) 的情况下工作,和一些不会的 JMockit 功能。是否有无法使用的功能列表?
    • 我认为任何 JMockit 注释都不起作用。你应该使用代码来模拟类。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-27
    相关资源
    最近更新 更多