Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 437
Sean Patrick Floyd Avatar asked Nov 14 '13 14:11

Sean Patrick Floyd


2 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.

like image 157
Sean Patrick Floyd Avatar answered Oct 11 '22 12:10

Sean Patrick Floyd


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

like image 30
FAB Avatar answered Oct 11 '22 13:10

FAB