0

Classes are compile time weaved. I read in the documentation that weaved classes would warn on classes constructed outside the container context but not outright error, yet I get the following test error in the maven build:

testExecuteCommand(SportTimeExecutionCommandTest): Error creating bean with name 'SportTimeExecutionCommand': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'timeStrategyAnalyzer' is defined

This is despite me running the test with the Mockito junit class runner.

@RunWith(MockitoJUnitRunner.class)
public class SportTimeExecutionCommandTest {

    private static final Integer SPORT_ID = 1; 


    @Mock
    private IdTimeRequestAdjuster idTimeRequestAdjuster ; 
    @Mock
    private StrategyAnalyzer<List<TimeStep>> strategyAnalyzer;
    @Mock
    private SportStepExecutor stepExecutor ; 
    @Mock
    private TimeRequestStrategy strategy ; 
    @Mock 
    private TimeStep step; 

    @Mock
    private Future<List<EventData>> future; 

    private SportTimeExecutionCommand command; 


    private List<TimeStep> steps = new ArrayList<TimeStep>(); 

    @Before
    public void setUp() throws Exception {

        command = new SportTimeExecutionCommand(SPORT_ID); 
        command.setIdTimeRequestAdjuster(idTimeRequestAdjuster);
        command.setStepExecutor(stepExecutor); 
        command.setStrategyAnalyzer(strategyAnalyzer); 
        when(idTimeRequestAdjuster.getCurrentValue(SPORT_ID)).thenReturn(strategy);
        when(strategyAnalyzer.calculateSteps(strategy)).thenReturn(steps); 
        steps.add(step); 
        when(stepExecutor.executeStep(SPORT_ID, step)).thenReturn(future); 
        when(future.get()).thenReturn(new ArrayList<EventData>()); 
    }

    @Test
    public void testExecuteCommand() throws InterruptedException, ExecutionException {
        command.executeCommand(); 
        verify(idTimeRequestAdjuster).getCurrentValue(SPORT_ID);
        verify(strategyAnalyzer).calculateSteps(strategy); 
        verify(stepExecutor).executeStep(SPORT_ID,step); 

    }

}

Implementation class for reference :

@Configurable(autowire=Autowire.BY_TYPE)
public class SportTimeExecutionCommand implements AdjustingCommand<List<EventData>,Integer>{

    private final static Logger logger = Logger.getLogger(SportTimeExecutionCommand.class.getName());

    @Autowired
    private IdTimeRequestAdjuster idTimeRequestAdjuster ; 

    @Resource(name = "timeStrategyAnalyzer")
    private StrategyAnalyzer<List<TimeStep>> strategyAnalyzer;

    @Autowired
    private SportStepExecutor stepExecutor ; 

    private final Integer sportId ; 

    public SportTimeExecutionCommand(Integer sportId)
    {
        this.sportId = sportId ;
    }

    @Override
    public List<EventData> executeCommand() throws InterruptedException, ExecutionException {
        List<EventData> eventData = new ArrayList<EventData>();
        List<TimeStep> timeSteps = strategyAnalyzer.calculateSteps(idTimeRequestAdjuster.getCurrentValue(sportId));
        List<Future<List<EventData>>> futureResults = new ArrayList<Future<List<EventData>>>();

        for (TimeStep timeStep : timeSteps) {
            futureResults.add(stepExecutor.executeStep(sportId, timeStep));
        }

        for (Future<List<EventData>> futureEventData : futureResults) {
            eventData.addAll(futureEventData.get());
        }


        return eventData;
    }

    @Override
    public Integer getCriteria() {
        return sportId; 
    }

    @Override
    public void adjust() {
        logger.warning("adjusting sportId "+sportId+" value is now : "+idTimeRequestAdjuster.getCurrentValue(sportId).getRequests()); 
        idTimeRequestAdjuster.adjustUp(sportId);
    }

    public void setIdTimeRequestAdjuster(IdTimeRequestAdjuster idTimeRequestAdjuster) {
        this.idTimeRequestAdjuster = idTimeRequestAdjuster;
    }

    public void setStrategyAnalyzer(StrategyAnalyzer<List<TimeStep>> strategyAnalyzer) {
        this.strategyAnalyzer = strategyAnalyzer;
    }

    public void setStepExecutor(SportStepExecutor stepExecutor) {
        this.stepExecutor = stepExecutor;
    }

}

Can someone see the problem ?

EDIT: I suspect that it processes the resources first which is why the error happens here. If I switch the annotation to autowired then it will break on the first autowired bean instead.

MikePatel
  • 2,593
  • 2
  • 24
  • 38
  • Ok solved the problem. The test was looking for beans in an directory I had **excluded** from the test context. Still i'm unsure how it has matched the context at all. Does it accumulate them all and look for all beans? Does it have some kind of way of managing conflicts ? Also why doesnt it work as described in 7.8.1.1 Unit testing @Configurable objects. Is it a spring bug ? – MikePatel Mar 28 '12 at 16:47

2 Answers2

1

I think that the problem is caused by name attribute in the @Resource annotation:

@Resource(name = "timeStrategyAnalyzer")
private StrategyAnalyzer<List<TimeStep>> strategyAnalyzer;

Probably, if you remove it, dependency injection performed by aspects will work fine - please note that actually you do not expose resource with this name anywhere in code you posted. Weaved classes constructed outside of Spring Container (using new operator) are also eligible for dependency injection.

omnomnom
  • 8,911
  • 4
  • 41
  • 50
  • I tried removing the qualifier before posting the question. Additionally I tried using autowired as an alternative but neither solved the problem. timeStrategyAnalyzer is a valid bean, I just didnt explicitly post it to avoid obfuscating the problem. – MikePatel Mar 28 '12 at 09:16
  • I'm also confused about the spring interaction here. As far as I can see i'm not explicitly starting the spring container (its run with the mockito junit runner), so how would the context be configured ? – MikePatel Mar 28 '12 at 09:18
  • So maybe that's because you have compile-time weaving - aspect tries to inject dependencies, but Spring container is not running. Can you please try to swith to runtime weaving just to try if it works properly? – omnomnom Mar 28 '12 at 11:21
  • runtime weaving I believe would work (based on 7.8.1.1 Unit testing @Configurable objects) but this I believe is not a good solution to force this kind of approach. – MikePatel Mar 28 '12 at 16:48
0

My solution was to run a seperate maven build profile which compiled without aspects, then in the integration phase compile with aspects.

MikePatel
  • 2,593
  • 2
  • 24
  • 38