一起使用JMockit和Spring AOP

7

假设我有一个像这样的程序:

@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运行它,它可以正常工作(主方法在创建Spring的mainAction之后实际上调用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在这里,但是没有处理任何模拟相关的东西。此外,我使用@Tested@Injectable代替@Autowired@Mocked,遵循这个问题中的建议;如果不这样做,mainAction仍然为 null。所以现在测试运行了,并且“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,使事情得以解决。
2个回答

3

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


是的,这应该可以工作。我只能补充一点,测试类的实例化/注入需要由Spring完成,否则切面将无法工作。为了模拟注入的“Logger”,测试需要使用@Capturing而不是@Injectable - Rogério
对我来说它不起作用。 我得到了Method testThatLoggerIsCalled should have no parameters(来自SpringJUnit4ClassRunner.java内部),如果我使用@RunWith(JMockit.class),我就不会得到这个错误。 我正在使用Maven依赖项,并将jmockit移动到了pom.xml中的junit之上(实际上,jmockit现在是第一个),并清理和重建了项目。 那么我还忘记做什么? - ajb
@Rogério,我仍然无法让它正常工作(请参见先前的评论)。 - ajb
现在我在考虑,也许我可以在没有方法参数的情况下让它工作。(明天会尝试。)(最初,当我遇到错误时,我认为我不能使用SpringJUnit4ClassRunner,所以我放弃了这个想法。)但是似乎可能有一些JMockit功能可以在没有@RunWith(JMockit.class)的情况下工作,而有些则不行。是否有一个不起作用的功能列表? - ajb
我认为任何JMockit注释都不会起作用。您应该使用代码来模拟类。 - Grasshopper
只要使用标准的JUnit测试运行器,JMockit的所有功能都可以在没有@RunWith(JMockit.class)的情况下工作;如果使用其他自定义测试运行器(例如SpringJUnit4ClassRunner),则可能会或可能不会工作,这取决于该自定义运行器的实现方式。 - Rogério

3

以下测试在使用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中注入还是其他地方? - ajb
这个关于“没有参数”的错误确实也出现在我这里,但只有当我使用基于旧JUnit 4.4测试运行器的Spring 2.5时。对于JMockit Spring Test 4.1,最低的JUnit版本是JUnit 4.5;它不能与3.8.1一起使用(但那可能是其他问题——您运行时类路径中的junit.jar很可能是JUnit 4.x)。 - Rogério
我会接受答案,以免悬赏过期。但我会继续努力获取正确的版本,并保持更新。 - ajb
通过将 System.getProperty("java.class.path") 打印到控制台来检查您的实际运行时类路径。请注意,Eclipse 在构建路径中有 两个 JAR 列表(其他 IDE 仅有一个列表,我不知道为什么它要这样做),并且在运行测试时不会将命令行打印到控制台,这使得查找类路径问题变得困难。 - Rogério
所以在这种情况下,http://jmockit.org/gettingStarted.html中建议使用Order和Export来排序jar文件似乎不够好;我必须完全从此选项卡中删除JUnit4,并仅在Maven中列出它。我想我已经看到其他stackoverflow问题推荐这样做(不确定,我得搜索一下)。但是我没有将我的问题与他们遇到的任何问题联系起来。 - ajb
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接