Is there a smart way to unit test AspectJ policy enforcement aspects?

I have several AspectJ policy enforcement aspects that are applied to my Maven src/main/java directory. Recently, some holes in these aspects have been discovered, so I would like to create unit tests for them.

What I'd like to do is create Java files in the test directory (which is not compiled by AspectJ), then programmatically invoke the AspectJ compiler on selected Files and making assertions based on the outcome.

Something like this would be perfect:

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

has anybody done anything similar?

Answers


As usual, here's my own answer:

I created a class called AbstractAspectJPolicyEnforcementTest. Some of the contents are proprietary information, but I'll show you the most important stuff:

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;
    }
}

And here's how I use it in a test class:

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")));
    }
}

Of course in a next step, I could extend this to allow to check for specific error messages, but for the beginning this will do.


I wrote a framework to isolate each aspect using Mocks and verify pointcut matching. It works with real or fictive methods calls and execution.

Maybe it might help you.

https://github.com/mock4aj/mock4aj


Need Your Help

How can I get a list of public exports from a .Net DLL?

c# .net dll

I can use tools like "dumpbin" and "dll export" to see the public entrypoints ("exports") of standard win32 DLL's like Windows\SYSTEM32\GDI32.dll. But when I use these same tools on .Net DLLs al...

I am wondering why I cannot override jquery function onRegionOver. The WAMP index.html file is shown below

javascript jquery html

I am wondering why I cannot override jquery function onRegionOver. The WAMP index.html file is shown below. Please tell me how I can use the WAMP console to debug this problem.