Why I obtain this error message when I try to move the configuration class as an inner class of the test class?

1.1k Views Asked by At

I am studying for the Spring Core certification and I have the following problem with an exercise related to the use of JUnit test in Spring.

So I have the following configuration class named TestInfrastructureConfig:

@Configuration
@Import({
    TestInfrastructureDevConfig.class,
    TestInfrastructureProductionConfig.class,
    RewardsConfig.class })
public class TestInfrastructureConfig {

    public LoggingBeanPostProcessor loggingBean(){
        return new LoggingBeanPostProcessor();
    }
}

This class configure the test environment-

Now in an exercise say that:

In Spring when no configuration class or configurationXML file is specified, @ContextConfiguration will look for an inner class marked with @Configuration (If none is found it will also look for an XML file name of <Classname>-context.xml). Since the TestInfrastructureConfig class is so small anyway, copy the entire class definition, including annotations, to an inner class withing the test class. Then remove the configuration class reference from the @ContextConfiguration annotation (no property in the brackets). This is an example of convention over configuration.

So I have totally commentd the code of the TestInfrastructureConfig class that become:

//package rewards;
//
//import org.springframework.context.annotation.Configuration;
//import org.springframework.context.annotation.Import;
//
//import config.RewardsConfig;
//
//@Configuration
//@Import({
//  TestInfrastructureDevConfig.class,
//  TestInfrastructureProductionConfig.class,
//  RewardsConfig.class })
//public class TestInfrastructureConfig {
//
//  public LoggingBeanPostProcessor loggingBean(){
//      return new LoggingBeanPostProcessor();
//  }
//}

Then in the RewardNetworkTests I change:

@ContextConfiguration(classes=TestInfrastructureConfig.class)

into:

@ContextConfiguration()

and I add the code of the commented TestInfrastructureConfig into the RewardNetworkTests class as an inner class, something like this:

@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(classes=TestInfrastructureConfig.class)
@ContextConfiguration()
//@ActiveProfiles("jdbc")
//@ActiveProfiles({ "jdbc", "jdbc-dev" })
@ActiveProfiles({ "jdbc", "jdbc-production" })
public class RewardNetworkTests {


    /**
     * The object being tested.
     */
    @Autowired
    private RewardNetwork rewardNetwork;

    @Test
    public void testRewardForDining() {
        // create a new dining of 100.00 charged to credit card
        // '1234123412341234' by merchant '123457890' as test input
        Dining dining = Dining.createDining("100.00", "1234123412341234",
                "1234567890");

        // call the 'rewardNetwork' to test its rewardAccountFor(Dining) method
        RewardConfirmation confirmation = rewardNetwork
                .rewardAccountFor(dining);

        // assert the expected reward confirmation results
        assertNotNull(confirmation);
        assertNotNull(confirmation.getConfirmationNumber());

        // assert an account contribution was made
        AccountContribution contribution = confirmation
                .getAccountContribution();
        assertNotNull(contribution);

        // the contribution account number should be '123456789'
        assertEquals("123456789", contribution.getAccountNumber());

        // the total contribution amount should be 8.00 (8% of 100.00)
        assertEquals(MonetaryAmount.valueOf("8.00"), contribution.getAmount());

        // the total contribution amount should have been split into 2
        // distributions
        assertEquals(2, contribution.getDistributions().size());

        // each distribution should be 4.00 (as both have a 50% allocation)
        assertEquals(MonetaryAmount.valueOf("4.00"), contribution
                .getDistribution("Annabelle").getAmount());
        assertEquals(MonetaryAmount.valueOf("4.00"), contribution
                .getDistribution("Corgan").getAmount());
    }   

    @Configuration
    @Import({
        TestInfrastructureDevConfig.class,
        TestInfrastructureProductionConfig.class,
        RewardsConfig.class })
    public class TestInfrastructureConfig {

        public LoggingBeanPostProcessor loggingBean(){
            return new LoggingBeanPostProcessor();
        }
    }
}

But when I try to run the test I obtain the red bar, the test is not passed, and the following error message:

java.lang.IllegalStateException: Neither GenericXmlContextLoader nor AnnotationConfigContextLoader was able to detect defaults, and no ApplicationContextInitializers were declared for context configuration [ContextConfigurationAttributes@52d455b8 declaringClass = 'rewards.RewardNetworkTests', locations = '{}', classes = '{}', inheritLocations = true, initializers = '{}', inheritInitializers = true, name = [null], contextLoaderClass = 'org.springframework.test.context.ContextLoader']
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.processContextConfiguration(AbstractDelegatingSmartContextLoader.java:200)
    at org.springframework.test.context.ContextLoaderUtils.buildMergedContextConfiguration(ContextLoaderUtils.java:703)
    at org.springframework.test.context.ContextLoaderUtils.buildMergedContextConfiguration(ContextLoaderUtils.java:656)
    at org.springframework.test.context.DefaultTestContext.<init>(DefaultTestContext.java:93)
    at org.springframework.test.context.TestContextManager.<init>(TestContextManager.java:122)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTestContextManager(SpringJUnit4ClassRunner.java:118)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.<init>(SpringJUnit4ClassRunner.java:107)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
    at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:31)
    at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:24)
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)
    at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:29)
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)
    at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:24)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.<init>(JUnit4TestReference.java:33)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestClassReference.<init>(JUnit4TestClassReference.java:25)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:48)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:452)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Why? What could be the problem? How can I try to solve this issue?

2

There are 2 best solutions below

0
On

I think your LoggingBeanPostProcessor method needs the @Bean annotation, not sure if that will solve the issue though

0
On

It's weird that the exercise says inner class. That is an error. What it actually means is a nested static class.

Declare your TestInfrastructureConfig class as static within the RewardNetworkTests class.

This is further described in the documentation, here. However, they still use the term inner class incorrectly. The JLS describes an inner class specifically as a non-static nested class. While reading the documentation, you should emphasize the static.