Sean Patrick Floyd
Sean Patrick Floyd

Reputation: 299098

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?

Upvotes: 6

Views: 709

Answers (2)

FAB
FAB

Reputation: 21

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

Upvotes: 2

Sean Patrick Floyd
Sean Patrick Floyd

Reputation: 299098

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.

Upvotes: 5

Related Questions