I'm trying to write test class for the following method
public class CustomServiceImpl implements CustomService {
@Value("#{myProp['custom.url']}")
private String url;
@Autowire
private DataService dataService;
I'm using the injected url value in one of the methods in the class. To test this i've written a junit class
@RunWith(MockitoJUnitRunner.class)
@ContextConfiguration(locations = { "classpath:applicationContext-test.xml" })
public CustomServiceTest{
private CustomService customService;
@Mock
private DataService dataService;
@Before
public void setup() {
customService = new CustomServiceImpl();
Setter.set(customService, "dataService", dataService);
}
...
}
public class Setter {
public static void set(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
}
In applicationContext-test.xml I'm loading the property file using
<util:properties id="myProp" location="myProp.properties"/>
But the url value is not getting loaded in the CustomService on running the test. I was wondering if there is anyway to get this done.
Thanks
You can autowire into a mutator (setter), rather than just annotating the private field. Then you can use that setter from your test class as well. No need to make it public, package private will do as Spring can still access it, but otherwise only your test can get in there (or other code in the same package).
I'm not a fan of autowiring differently (compared to my codebase) just for testing, but the alternative of changing the class under test, from the test, is simply unholy.
I agree with the comment of @skaffman.
Besides your test uses the
MockitoJUnitRunner
, hence it won't look for any Spring stuff, this only purpose is to initialize Mockito mocks. TheContextConfiguration
is not enough to wire things with spring. Technically with JUnit you can use the following runner if you want spring related stuff :SpringJUnit4ClassRunner
.Also as you are writing a Unit Test you might want to reconsider the use of spring. Using spring wiring in a unit test is wrong. However if you are instead writing an Integration Test then why are you using Mockito there, it doesn't make sense (as said by skaffman) !
EDIT: Now in your code your a directly setting the
CustomerServiceImpl
in your before block, that doesn't makes sense either. Spring is not involved at all there !EDIT 2: If you want to write a Unit Test of
CustomerServiceImpl
, then avoid Spring stuff and inject directly the value of the property. Also you could use Mockito to inject theDataService
mock straigth into the tested instance.As you might have noticed I'm using a direct access to the
url
field, the field can be package visible. This is a test workaround to actually inject the URL value as Mockito only injects mocks.I had a List of strings reading from Properties file. ReflectionTestUtils class setField method used in @Before block helped me set these values prior to my test execution . It worked perfect even for my dao layer which is depending on Common DaoSupport class.
You should not mock the thing that you are trying to test. That is pointless since you would not be touching any of the code you are trying to test. Instead get the instance of
CustomerServiceImpl
from the context.You can use this little utility class (gist) to automatically inject field values into a target class:
It uses
org.apache.commons.lang3.reflect.FieldUtils
to access all fields annotated with@Value
and then uses Spring utility classes to resolve all placeholder values. You can also change the type of parameterproperties
toPlaceholderResolver
in case you like to use your own PlaceholderResolver. In your test, you can use it to inject a set of values given as aMap
orProperties
instance like in the following example:This will then try to resolve all
@Value
annotated fields in yourdataService
. I personally prefer this solution overReflectionTestUtils.setField(dataService, "field", "value");
as you don't have to rely on hardcoded field names.