Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking a Properties file with Mockito in Spring

I am trying to write a unit test for the following method in my controller.

@Autowired
    private ApplicationContext context;

    private String getProperty() {
        try {
            Properties props = context.getBean("myProperties", Properties.class);
            String val = props.getProperty("myProperty");
......

The Bean is declared like this in my applicationContext:

<util:properties id="myProperties" scope="prototype" location="file:${catalina.base}/webapps/myProperties.properties"/>

How can I mock this so that I can test different values of the val variable?

I thought about creating a test properties file and mocking it like this:

context = Mockito.mock(ApplicationContext.class);
Mocikto.when(context.getBean("myProperties", Properties.class)).thenReturn(some test file)

but then I would have to declare the test file as a bean somewhere.

I was wondering if there was an easier way to do this?

Thanks

like image 204
blong824 Avatar asked Jun 17 '11 16:06

blong824


3 Answers

If you're using spring-3, you can do:

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

And in your code:

@Value("${myProperty}")
private String myProp;

public String getMyProp() {
    return myProp;
}

This causes myprops.properties to be made available for variable substitutions via ${...} expressions, and the @Value annotation allows value injection of properties. Then in your unit test you can simply set different values of myProp.

like image 124
Kevin Avatar answered Oct 14 '22 05:10

Kevin


The easier way is to use a org.springframework.beans.factory.config.PropertyPlaceholderConfigurer instead of pulling the properties explicitly from the spring application context. The PropertyPlaceholderConfigurer injects your bean with the properties you specify. Then you don't need Mockito at all, in the test you set the property value in the Controller to whatever you want it to be.

So you'd set up the configurer in the application context xml:

<context:property-placeholder 
  location="file:${catalina.base}/webapps/myProperties.properties"/>

and add some configuration for your controller (I expect there's a way to do this with annotations but don't know it):

 <bean id="whateverMyControllerIdIs" class="com.initech.foobar.MyControllerImpl">
   <property name="quux"><value>${myProperty}</value></property>
 </bean>

where the controller has an instance variable that you want to populate with the property, with a setter, like this:

String quux;

public void setQuux(String quux) {this.quux = quux;}

Just saw a blog post on Spring 3.1 enhancements, here's the new xml-free way to do this:

    @Configuration
@PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {
    @Autowired
    Environment env;

    @Bean
    public TestBean testBean() {
        TestBean testBean = new TestBean();
        testBean.setName(env.getProperty("testbean.name"));
        return testBean;
    }
}
like image 22
Nathan Hughes Avatar answered Oct 14 '22 03:10

Nathan Hughes


So I can test without having to load the Spring Context I use a Config class for accessing all of the properties file(s) values from within code. The benefits are:

1) Spring doesn't load in your unit tests

2) You can force an Exception if the property is missing and it is required

3) You can return strongly type property values from the getter() methods (i.e. convert to a Date)

4) The "key" values expected from your properties files are documented in a single Java class (i.e. public static final PROP_XXX)

@Component
public class Config {

public static final String PROP_USER_NAME = "user.name";

private Properties applicationProperties;


/*** Functional methods ***/

/**
 * Helper method to ensure consistent Exception handling where requested property values are missing
 * from the properties files and they are "required" for the application to function correctly.
 *
 * @param key
 * @return The String value of the property requested
 */
private String readPropertyRequired(String key) {

    String value = readProperty(key);

    if(StringUtils.isBlank(value))  {
        throw new PropertyNotFoundException(key);
    }

    return value;
}

/**
 * Helper method to return String values from the properties files that have been loaded
 *
 * @param key
 * @return The String value of the property requested or NULL if empty
 */
private String readProperty(String key) {
    return applicationProperties.getProperty(key);
}


/*** Getters & Setters ***/

@Autowired
public void setApplicationProperties(Properties applicationProperties) {
    this.applicationProperties = applicationProperties;
}

public String getUserName() {
    return readPropertyRequired(PROP_USER_NAME);
}

}

You can then unit test this class by simply injecting a standard java.util.Properties

like image 1
Brad Avatar answered Oct 14 '22 03:10

Brad