Search code examples
springaspectjspring-aop

Aspect testing - can't get right value of aspects bean's property


Aspect

@Configurable
@Aspect
public class FilmCounter {

    private Map<Integer, Integer> filmCounts = 
            new HashMap<Integer, Integer>();

    @Pointcut(
        "execution(* soundsystem.CompactDisc.play(int)) " +
        "&& args(filmNumber)" )
    public void filmPlayed(int filmNumber) {}

    @Before("filmPlayed(filmNumber)")
    public void countFilm(int filmNumber){      
        int currentCount = getPlayCount(filmNumber);
        filmCounts.put(filmNumber, currentCount + 1);

        System.out.println("filmNumber " + filmNumber + " contains in ? " + filmCounts.containsKey(filmNumber) + " then filmCount = " + filmCounts.get(filmNumber));

    }

    public int getPlayCount(int filmNumber){
        //System.out.println("filmNumber " + filmNumber + " contains in ? " + filmCounts.containsKey(filmNumber) + "");

        return filmCounts.containsKey(filmNumber)
                ? filmCounts.get(filmNumber) : 0;

    }
}

Configuration class

Under AspectJ runtime lib so not needed @EnableAspectJAutoProxy annotation

@Configuration
public class FilmCounterConfig {

    @Bean
    public CompactDisc filmDisk(){
        FilmDisc cd = new FilmDisc();
        cd.setTitle("1981's Melody Films");
        cd.setArtist("Kishor Kumar");
        List<String> films = new ArrayList<String>();
        films.add("Sanam Teri Kasam");
        films.add("Akhari Rasta");
        films.add("Hum Apke Hai Koun");
        films.add("Dil Hain Ke Manata Nahi");
        films.add("Hum Sath Sath Hain");
        cd.setFilms(films);

        return cd;
    }   

    @Bean
    public FilmCounter filmCounter(){
        return new FilmCounter();
    }
}

Test class

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=FilmCounterConfig.class)
public class FilmCounterTest {

    @Rule
    public final SystemOutRule systemOutRule = new SystemOutRule().enableLog(); 

    @Autowired
    private CompactDisc cd;

    @Autowired
    private FilmCounter counter;

    @Test
    public void testFilmCounter(){

        cd.play(1); System.out.println("counter.getPlayCount(1) = " + counter.getPlayCount(1));
        cd.play(2);
        cd.play(3);
        cd.play(3);
        cd.play(3);
        cd.play(3);     

        /*assertEquals(1, counter.getPlayCount(1));
        assertEquals(1, counter.getPlayCount(2));
        assertEquals(4, counter.getPlayCount(3));
        */

        System.out.println("Film 1 = " + counter.getPlayCount(1));
        System.out.println("Film 2 = " + counter.getPlayCount(2));
        System.out.println("Film 3 = " + counter.getPlayCount(3));

    }

}

When running the above test case I get the following output:

Console log

The image shows that the console log output for the first method call cd.play(2); looks OK, but after invoking System.out.println("Film 1 = " + counter.getPlayCount(1)); it shows the wrong result (it should display "4" but displays "0").


Solution

  • I think I know what is going on, looking at your console log: There is an active aspect instance recording your method calls, but probably not the same one as is wired into your test. This would explain the discrepancy between the aspect log output versus the test log output.

    If you add System.out.println(this); to the countFilm(int) advice and System.out.println(counter); to the test case, I guess you will probably see two different object IDs.

    If I am right, something is wrong with your with your bean wiring. Please provide feedback here in a comment.