Shush
Shush

Reputation: 77

Modify a parameter value used in multiple beans in Java unit test

I'm wrting a JUnit to test a threshold value, which is passed from a .properties file like:

threshold=8

And I use a spring context to apply this threshold value:

<context:property-placeholder location="classpath:test.properties"/>

<si:channel id="thresholdInputChannel"/>
<si:recipient-list-router input-channel="thresholdInputChannel" default-output-channel="nullChannel">
    <si:recipient channel = "recipientChannel" selector-expression = "${threshold} > 0"/>
</si:recipient-list-router>
...

<si:chain input-channel = "fileTransformationChannel" output-channel="endChannel">
    <si:transformer method = "transform">
        <bean class = "fileTransformer" >
            <property name = "fixedProperties">
                <map>
                    <entry key="threshold" value="${threshold}"/>
                </map>
            </property>
        </bean>
    </si:transformer>
</si:chain>
...

Before in the JUnit test, I used @ContextConfiguration(locations = {"classpath:test.properties"}) to load the context and @RunWith(SpringJUnit4ClassRunner.class) and @Autowired to get all the channels defined in context file and it worked fine. But the problem is that like this I can test at one time one single value of ${threshold} which is predefined in the test.properties.

To be able to change ${threshold} value, I tried all the ways mentioned in this answer:

  1. Use @RunWith(Parameterized.class)

    @Parameterized.Parameters
    public static List<Object[]> params() {
        return Arrays.asList(new Object[][]{
                {"0"},
                {"8"},
        });
    }
    

    but in this way I can't use injected beans any more, hence I lost the channels in JUnit.

  2. public abstract class AbstractJunitTest extends AbstractJUnit4SpringContextTests same problem with injected beans.

  3. @Value("${threshold}") private String threshold; origin value don't get erased and invoke a problem of variable type as there is selector-expression = "${threshold} > 0" in context file.

I'd like to know if there is any other possible ways to do this. Dropping the context file and creating an ApplicationConfig.class with all the beans and parameters may be a solution but not a prefered one, as the context file is really great.

By the way, the reason I have to autowire the channels in JUnit is that I have to send a local file into the fileTransformationChannel and get it transformed in some way.

Upvotes: 0

Views: 1468

Answers (1)

Lucas Oliveira
Lucas Oliveira

Reputation: 883

you can use org.springframework.test.context.TestContextManager for this:

Exemple:

@RunWith(Parameterized.class)
@SpringBootTest(classes = Application.class)
public class TargetClassTest {

    @Autowired
    private TargetClass instance;

    private TestContextManager testContextManager;

    String threshold;

    @Before
    public void setUpContext() throws Exception {
        this.testContextManager = new TestContextManager(getClass());
        this.testContextManager.prepareTestInstance(this);
    }


    @Parameters
    public static Collection<Object []> data() {
        return Arrays.asList(new Object[][]{
            {"0"},{"8"},
        });
    }

    public TargetClassTest(String test) {
        this.threshold = test;
    }

    @Test
    public void testSomething() throws Exception {
        String r = instance.businessMethod(threshold);
        Assert.assertEquals(threshold, r);
    }
}

In this case, it is possible after the initialization of @Before "inject" your Spring bean and use the parameterized execution to test several scenarios.

Upvotes: 1

Related Questions