【问题标题】:Is there a smart way to unit test AspectJ policy enforcement aspects?是否有一种聪明的方法来对 AspectJ 策略执行方面进行单元测试?
【发布时间】:2013-11-27 15:41:15
【问题描述】:

我有几个应用于我的 Maven src/main/java 目录的 AspectJ 策略实施方面。最近发现了这些方面的一些漏洞,所以我想为它们创建单元测试。

我想做的是在测试目录中创建 Java 文件(不是由 AspectJ 编译的),然后以编程方式在选定的文件上调用 AspectJ 编译器并根据结果进行断言。

这样的东西会很完美:

assertThat("MyJavaClass.java", producesCompilerErrorFor("SomeAspect.aj"));

有人做过类似的吗?

【问题讨论】:

  • 如果你在 Windows 上,ajc 是一个批处理文件。只需查看该命令行,然后执行它。认为您需要的只是类路径上的 ajtools.jar,但我忘记了主类的名称。
  • 不是一个选项。测试必须在许多不同平台上的许多不同机器上运行,而无需任何人在本地安装 ajc
  • 如果没有 aspectj 编译器,您打算如何编译 SomeAspect.aj?
  • 我已经在做。是通过maven引用的,但是本地没有安装脚本
  • 不要使用脚本,只检查命令行的脚本。然后你可以自己调用main方法,在producesCompilerErrorFor(*)中。

标签: java unit-testing maven aop aspectj


【解决方案1】:

我编写了一个框架来使用 Mocks 隔离各个方面并验证切入点匹配。它适用于真实或虚构的方法调用和执行。

也许对你有帮助。

https://github.com/mock4aj/mock4aj

【讨论】:

  • 不错!会检查的!
【解决方案2】:

像往常一样,这是我自己的答案:

我创建了一个名为AbstractAspectJPolicyEnforcementTest 的类。有些内容是专有信息,但我会向您展示最重要的内容:

protected Matcher<File> producesCompilationErrorWith(final File aspectFile) {
    return new AspectJCompilationMatcher(aspectFile, Result.ERROR);
}

private class AspectJCompilationMatcher extends TypeSafeMatcher<File> {
    private final File aspectFile;
    private final Result expectedResult;
    private Result result;

    public AspectJCompilationMatcher(final File aspectFile, final Result expectedResult) {
        this.aspectFile = aspectFile;
        this.expectedResult = expectedResult;
    }

    @Override
    protected boolean matchesSafely(final File javaSourceFile) {
        result = compile(javaSourceFile, aspectFile);
        return result == expectedResult;
    }

    @Override
    public void describeTo(final Description description) {
        description.appendText("compilation result: ").appendValue(result);
    }
}

enum Result {
    ERROR,
    WARNING,
    SUCCESS
}

private Result compile(final File javaFileName, final File aspectFile) {

    assertExists(javaFileName);
    assertExists(aspectFile);

    List<String> argList = newArrayList();

    // java 7 compatibility
    argList.add("-source");
    argList.add("1.7");
    argList.add("-target");
    argList.add("1.7");

    // set class path
    argList.add("-cp");
    argList.add(System.getProperty("java.class.path"));

    // add java file
    argList.add(javaFileName.getAbsolutePath());

    // add aspect files
    argList.add(aspectFile.getAbsolutePath());
    for (File additionalAspectFile : requiredAspects) {
        assertExists(additionalAspectFile);
        argList.add(additionalAspectFile.getAbsolutePath());
    }

    String[] args = argList.toArray(new String[argList.size()]);
    List<String> fails = newArrayList();
    List<String> errors = newArrayList();
    List<String> warnings = newArrayList();
    List<String> infos = newArrayList();

    // org.aspectj.tools.ajc.Main;
    Main.bareMain(args, false, fails, errors, warnings, infos);
    if (!fails.isEmpty() || !errors.isEmpty()) {
        return Result.ERROR;
    } else if (!warnings.isEmpty()) {
        return Result.WARNING;
    } else {
        return Result.SUCCESS;
    }
}

这是我在测试类中使用它的方式:

public class ForbiddenPackageNameAspectTest extends AbstractAspectJPolicyEnforcementTest {
    @Test
    public void testBadPackageName() throws Exception {
        assertThat(sourceFile(BadJavaClass.class),
            producesCompilationErrorWith(findAspect("ForbiddenPackageNameAspect")));
    }

    @Test
    public void testGoodPackageName() throws Exception {
        assertThat(sourceFile(ForbiddenPackageNameAspectTest.class),
                compilesWithoutWarningWith(findAspect("ForbiddenPackageNameAspect")));
    }
}

当然,在下一步中,我可以扩展它以允许检查特定的错误消息,但一开始就可以。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-02
    • 1970-01-01
    相关资源
    最近更新 更多