Why ZonedDateTime.now() throws NoSuchMethodException while running test cases(using mockito) - java

Lately I am writing junit test cases and I came across ZonedDateTime.now() works partially expected where the method which we try to write test case uses DozerBeanMapper for copying common fields. Please go through below to have better understanding btw I am using #Spy for DozerBeanMapper not #Mock because #Mock provides me dummy Object which troubles while I assert at the end.
class A {
#Autowired
DozerBeanMapper mapper;
Entity method(Request req) {
Entity ent = new Entity();
req.setCreatedOn(ZonedDateTime.now());
dozerMapper.map(req,ent);
return ent;
}
}
Throws exception for above code :
org.dozer.MappingException: java.lang.NoSuchMethodException: java.time.LocalDateTime.<init>()
at org.dozer.util.MappingUtils.throwMappingException(MappingUtils.java:82) ~[dozer-5.4.0.jar:na]
at org.dozer.factory.ConstructionStrategies$ByConstructor.newInstance(ConstructionStrategies.java:261) ~[dozer-5.4.0.jar:na]
at org.dozer.factory.ConstructionStrategies$ByConstructor.create(ConstructionStrategies.java:245) ~[dozer-5.4.0.jar:na]
at org.dozer.factory.DestBeanCreator.create(DestBeanCreator.java:65) ~[dozer-5.4.0.jar:na]
at org.dozer.MappingProcessor.mapCustomObject(MappingProcessor.java:489) [dozer-5.4.0.jar:na]
at org.dozer.MappingProcessor.mapOrRecurseObject(MappingProcessor.java:446) [dozer-5.4.0.jar:na]
at org.dozer.MappingProcessor.mapFromFieldMap(MappingProcessor.java:342) [dozer-5.4.0.jar:na]
at org.dozer.MappingProcessor.mapField(MappingProcessor.java:288) [dozer-5.4.0.jar:na]
But It works absolute fine when I alter and add setCreatedOn after dozerMapper maps like below and I know this one is the correct way.
Class A {
#Autowired
DozerBeanMapper mapper;
Entity method(Request req){
Entity ent = new Entity();
dozerMapper.map(req,ent);
ent.setCreatedOn(ZonedDateTime.now());
return ent;
}
}
My whole point is why it does not work for first method code?
Here is the sudo test method
Class ATest {
#InjectMocks
A aService;
#Spy
DozerBeanMapper mapper;
#Test
void methodTest(){
aService.method(req);
}
}
I want an brief explanation why first code does not work?

Because dozer is attempting to create an instance of ZonedDateTime without knowing how, so it applies the usual strategy:
Call the no-args constructor, find set methods to invoke.
Call the no-args constructor, set the fields directly.
Find a constructor that takes 1 of each arg in turn.
And ZonedDateTime has none of those - the 'formula' to make one is to call .of(...) or now() or parse(...) - hence, failure.
That exception means: "I tried to invoke new ZonedDateTime() but this did not work, as that constructor does not exist". At the bytecode/JVM level, constructors are, effectively, public static OwnType <init>(args) {} - they are 'methods' whose name is <init>. Hence, java.lang.NoSuchMethodException: java.time.LocalDateTime.<init>().
This is thrown by dozer's mapper infrastructure: It is trying to take some data from some source and 'map that' into an instance of ZonedDateTime.
Check the dozer documentation on how to provide to provide it the functions it needs to do this mapping. Perhaps this gist is what you need.

Related

Java constraint validation doesn't work for parameters [duplicate]

This question already has answers here:
Same class invoke NOT effective in Spring AOP cglib [duplicate]
(2 answers)
Closed 3 years ago.
I want use java bean validation annotations for parameters of my spring services. Consider following service:
public interface MyService {
void methodA();
void methodB(#NotBlank String param)
}
with implementation:
#Validated
public class MyServiceImpl implements MyService {
#Override
public void methodA() {
String param = "";
methodB(param)
}
#Override
public void methodB(#NotBlank String param) {
// some logic
}
}
Can you tell me how to fire validation and throw constraint exception when passed string is blank? When I call service this way:
#Autowired
MyService myService;
myService.methodB("");
When methodB is called from another class, a constraint exception is thrown as expected.
But when the same methodB ias called form MethodA, no exception is thrown. Why no exception is thrown, if the same method with the same parameter is called?
In addition to the other answers and the fact you are aware of the AOP proxies existance let me just point you to the relevant chapter in Spring documentation which mentiones self-invocation problem with AOP proxies that you've come across:
public class Main {
public static void main(String[] args) {
ProxyFactory factory = new ProxyFactory(new SimplePojo());
factory.addInterface(Pojo.class);
factory.addAdvice(new RetryAdvice());
Pojo pojo = (Pojo) factory.getProxy();
// this is a method call on the proxy!
pojo.foo();
}
}
fun main() {
val factory = ProxyFactory(SimplePojo())
factory.addInterface(Pojo::class.java)
factory.addAdvice(RetryAdvice())
val pojo = factory.proxy as Pojo
// this is a method call on the proxy!
pojo.foo()
}
The key thing to understand here is that the client code inside the main(..) method of the Main class has a reference to the proxy. This means that method calls on that object reference are calls on the proxy. As a result, the proxy can delegate to all of the interceptors (advice) that are relevant to that particular method call. However, once the call has finally reached the target object (the SimplePojo, reference in this case), any method calls that it may make on itself, such as this.bar() or this.foo(), are going to be invoked against the this reference, and not the proxy. This has important implications. It means that self-invocation is not going to result in the advice associated with a method invocation getting a chance to execute.
-- https://docs.spring.io/spring/docs/5.2.3.RELEASE/spring-framework-reference/core.html#aop-understanding-aop-proxies
In the next paragraph two solutions are proposed (or in fact three, but switching to AspectJ in this particular case might turn out cumbersome):
Okay, so what is to be done about this? The best approach (the term, “best,” is used loosely here) is to refactor your code such that the self-invocation does not happen. This does entail some work on your part, but it is the best, least-invasive approach. The next approach is absolutely horrendous, and we hesitate to point it out, precisely because it is so horrendous. You can (painful as it is to us) totally tie the logic within your class to Spring AOP, as the following example shows:
public class SimplePojo implements Pojo {
public void foo() {
// this works, but... gah!
((Pojo) AopContext.currentProxy()).bar();
}
public void bar() {
// some logic...
}
}
class SimplePojo : Pojo {
fun foo() {
// this works, but... gah!
(AopContext.currentProxy() as Pojo).bar()
}
fun bar() {
// some logic...
}
}
This totally couples your code to Spring AOP, and it makes the class itself aware of the fact that it is being used in an AOP context, which flies in the face of AOP. It also requires some additional configuration when the proxy is being created, as the following example shows:
public class Main {
public static void main(String[] args) {
ProxyFactory factory = new ProxyFactory(new SimplePojo());
factory.addInterface(Pojo.class);
factory.addAdvice(new RetryAdvice());
factory.setExposeProxy(true);
Pojo pojo = (Pojo) factory.getProxy();
// this is a method call on the proxy!
pojo.foo();
}
}
fun main() {
val factory = ProxyFactory(SimplePojo())
factory.addInterface(Pojo::class.java)
factory.addAdvice(RetryAdvice())
factory.isExposeProxy = true
val pojo = factory.proxy as Pojo
// this is a method call on the proxy!
pojo.foo()
}
Finally, it must be noted that AspectJ does not have this self-invocation issue because it is not a proxy-based AOP framework.
-- https://docs.spring.io/spring/docs/5.2.3.RELEASE/spring-framework-reference/core.html#aop-understanding-aop-proxies
Spring validation is invoked when a managed bean calls another managed bean.
However, spring context is unaware of calls between methods within the same bean, ie intrabean rather than interbean, so #Validation has no influence.
One simple solution is to move the wrapper method out of the class into a utility method, something like:
public static void methodA(MyService myService) {
myService.methodB("");
}
There is no annotation #Validation in Spring. I think you meant #Validated.
To validate parameters, Spring creates kind of proxy using CGLIB. This is mechanism similar to what Spring uses for transactions. Spring adds this code only if your class MyServiceImpl is called from another class, i.e. where a control flow crosses the border between two classes. When you call your methodB from another class, Spring adds validation code. When you call it from the same class, Spring adds no code and thus no validation is triggered.

Unit Testing and Mocking - Approach and Practice for Deeper Hierarchies - Junit and EasyMock

I have a hierarchical list of converters like the following for example:
#Named
public class NameConverter {
#Inject
private AddressConverter addressConverter;
public package2.Name convert(package1.Name source) {
package2.Name target = new package2.Name();
target.setFirstName(source.getName());
target.setLastName(source.getName());
target.setAddress(addressConverter.convert(source.getAddress()));
}
}
and AddressConverter has ZipCodeConverter and so on ...
In the Unit Testing class,
1) I would create a mock for addressConverter - EasyMock.createNiceMock.
2) Set the expectation -
EasyMock.expect(addressConverter.convert(EasyMock.anyObject(package1.Address.class))).andReturn(addressList); # What this addressList should be?
3) Whitebox.setInternalState for private fields.
Question :
I would assert on first name and last name if they are equal which is straight forward.
But, NameConverter is also responsible for setting the converted Address.There is a possibility for NameConverter to change the values of returned converted Address and other POJOs inside.
So how do I ensure through Asserts or something else, that NameConverter just sets the Address(and the POJOs encapsulated by it) as it is and does not tamper with the values ??
Possible Solution: In the EasyMock.expect return, should I create and set values for all POJOs till the last one in the hierarchy and assert on each of the values?
But that doesn't seem like unit testing !!
Please help as how to unit test this converter.
It is unit testing to set the return value of a mock object and to assert that that return value is put in the right place by your NameConverter.
However, perhaps what you're coming across is a failure of appropriate layering. If you have a set of 'converter' classes which then need to be co-ordinated in some fashion you may want to make each converter independent and to bring the co-ordination responsibility elsewhere. So, your NameConverter should be completely independent of AddressConverter and you perhaps need a third class which is responsible for calling a set of converters, which each just do their job. You could restructure each converter to be given an instance of both their input and output object and their unit tests assert that they only act on known fields within each object. Then the co-ordinator object doesn't need to know anything about what each converter does, it just needs to locate / create instances of the input and output objects and to call each converter in turn. That's very amenable to a unit-testing approach, without resulting in a lot of layering concerns.
Example code:
public interface Converter<S, T> {
convert(S source, T target);
}
public class NameConverter implements Converter<p1.Name, p2.Name> {
#Override
public void convert(p1.Name source, p2.Name target) {
target.setFirstName(source.getName());
target.setLastName(source.getName());
}
}
public class AddressConverter implements Converter<p1.Name, p2.Name> {
#Override
public void convert(p1.Name source, p2.Name target) {
// more stuff.
}
}
public class ConversionService {
private final Set<Converter> converters;
#Inject
public ConversionService(Set<Converter> converters) {
this.converters = converters;
}
public p2.Name convert(p1.Name source) {
p2.Name target = new p2.Name();
converters.forEach((converter) -> converter.convert(source, target);
return target;
}
}
Then your unit test really just need to know that all your lower-level converters were called.
I would suggest three options:
Return a new empty instance of address from your mock and compare that the same exact instance is set to the target. Don't test if the address value is modified. It's Ok not to test every single possibility of things going wrong.
Return a strict mock of address without any expectations set. It will throw if there is an attempt to modify it. And again check for instance equality.
Don't use mocks at all. Test the entire hierarchy as a whole. It does not look like unit testing, but it may be a good option. I think mocks are often overused and should be avoided when possible. Please see more here.
I would recommend the following as a good unit test for NameConverter:
public final class NameConverterTest {
#SUT
NameConverter tested;
#Test
public void convertNameFromPackage1ToNameFromPackage2() {
Address address = new Address();
package1.Name source = new package1.Name("A Name", address);
package2.Name converted = tested.convert(source);
assertEquals(source.getName(), converted.getFirstName());
assertEquals(source.getName(), converted.getLastName());
assertNotNull(converted.getAddress());
}
}
According to Martin Fowler's definition, the above is still a unit test for the NameConverter unit, even if it doesn't isolate it from its dependency on AddressConverter (which would have its own unit test).
(For simplicity, I used an hypothetical #SUT annotation which takes care of instantiating the "system under test" with injected dependencies - and actual testing libraries for this do exist.)

JUnit/Spring/Mockito - Unable to mock class returned from another class implementing ApplicationContextAware

I am new to Spring and JUnit. I need to mock a class which is derived from ApplicationContextAware class which is inside my toBeTested(getList) method. In the following short code snippet, I need to test the getList method in abc class.
I am able to mock ModulesConfigRegistry because there is a setter for it. But I am not able to mock ModuleConfig and ListProvider. Both ModulesConfigRegistry and ModuleConfig have implemented ApplicationContextAware so it returns classes from bean. ListProvider.getList(lst.getList in code) is the method which makes further calls up to database and is required to be mocked. Appreciate your help in advance. Code sample will be helpful as I am new to Spring and JUnit.
class abc {
private ModulesConfigRegistry modulesConfigRegistry;
public void setModulesConfigRegistry(ModulesConfigRegistry modulesConfigRegistry) {
this.modulesConfigRegistry = modulesConfigRegistry;
}
public List getList(String name, String moduleName)
{
ModuleConfig moduleConfig = modulesConfigRegistry.getModuleConfig(moduleName);
Object mlist = moduleConfig.getListProvider(name);
if(mlist instanceof ListProvider)
{
ListProvider lst = (ListProvider)mList;
}
return lst.getList("abc");
}
}
Maybe there is another more simple way to achieve this (not mandatory the best). In my experience I've used Reflection in Java when it's up to Unit-testing. After all, to me the main purpose of the unit tests is to simply exercise smallest testable part and nothing more. That's why I simply use my dummy-test-object and get/set fields/properties I need.
But one thing that must be considered here is that reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects. So if you know what your doing it's a good alternative.
Since you already using
JUnit
One very common use case in Java is the usage with annotations. JUnit 4, for example, will use reflection to look through your classes for methods tagged with the #Test annotation, and will then call them when running the unit test.
If you want to consider it and use it - here you can find some good examples.
Cheers.
One approach here is create mock objects for each object that you need to interact with ModuleConfig and ListProvider
#RunWith(MockitoJUnitRunner.class)
public class abcTest{
#InjectMocks
private abc abcInstance;
#Mock
private ModulesConfigRegistry modulesConfigRegistry ;
#Test
private voidTestGetList(){
//Create the mock and interactions
ModuleConfig moduleConfigMock = Mockito.mock(ModuleConfig.class);
ListProvider listProviderMock = Mockito.mock(ListProvider.class);
ArrayList listToReturn = new ArrayList();
Mockito.when(modulesConfigRegistry.getModuleConfig(Mockito.anyString())).thenReturn(moduleConfigMock);
Mockito.when(moduleConfigMock.getListProvider(Mockito.anyString())).thenReturn(listProviderMock);
Mockito.when(listProviderMock.getList(Mockito.anyString())).thenReturn(listProviderMock);
//Call real method
List resultList = abcInstance.getList("stringInput1", "stringInput2");
//Make assertions
}
}
Basically you need to create mock objects for any of the instances that you get from a mock object and use mockito to define the result of its method.
Other options is create a new class that implements or is a subclass of the returned object type and override the methods.

Test Method Called Without Having Argument In Test Class

I have a class which takes a message with payload String.
The payload is then split and used to create an Entity which is passed to DAOInterface to persist.
How can you test the call daoInterface.insert(entity) has been made?
To Mock the DAOInterface and then verify the call to DAO requires the entity in the test class i.e.
verify(daoInterface).insert(entity);
Is this bad design i.e. creating the entity at this stage? Should the Sting[] split be passed to the DAOImplementaion and initialized there. Example problem,
public class ServiceClass {
#AutoWire
private DAOInterface daoInterface;
public void serviceMessage(Message<String> message) {
MessageHeaders mh = new MessageHeaders(message.getHeaders());
String[] split = ((String) mh.get("payload")).split("_");
code omitted
...
String type = mh.get("WhatType");
Entity entity = new Entity(split[0], split[1], split[2]);
if (type.equals("one"))
{
daoInterface.insert(entity); //How to test?
}
else
{
if (type.equals("two"))
{
doaInterface.modify(entity); //How to test?
}
}
}
}
You can verify with Mockito Matchers.
If you only care that the method is called with some Entity, you can verify that with
verify(daoInterface).insert(any(Entity.class));
If you care about which Entity, and the Entity class has an equals method, you can make an entity that should be equal to the one created and verify with
verify(daoInterface).insert(eq(expectedEntity);
If it's more complex than either of these cases, you can also write your own argument matchers.
The easiest thing you can do is injecting another collaborator to the service which will transform payload to Entity. This way you can keep control on object creation (Inversion of Control). Something like the example below injected to the ServiceClass should do the job:
interface PayloadTransformer {
public Entity transform(String payload);
}
This way your code will be easy to test and you split responsibilities which is usually a good thing. Have a look on Single Responsibility principle
Pushing transformation logic down to dao is almost never a good idea.
BTW. you can write else if without additional brackets and indentations. It's more readable like:
if (a) {
// do something
} else if (b) {
// do something
} else {
// do something
}
The last advice ServiceClass is really poor name for class. The word class is redundant here. Just name it Service, EntityService, MessageService or something which fits your case well.
I wouldn't name field with suffix *Interface as well. Underneath is some implementation injected, I assume. Better name it entityDao or just dao. It's up to you though :)
If you use a test framework like PowerMock, you can invoke private constructors and private methods in your test. This makes it easy to inject mock objects like a mock DAOInterface so you can retrieve it later and test it's been called.
For example, in PowerMock, to call a private constructor:
public class ServiceClass{
#Autowire
private final DAOInterface dao;
public ServiceClass() {
}
private ServiceClass(DAOInterface dao) {
this.dao = dao;
}
}
You simply do:
PrivateConstructorInstantiationDemo instance = WhiteBox.invokeConstructor(
PrivateConstructorInstantiationDemo.class,
new MockDAOInterface() );
So if you're using a dependency inject framework like above, this dovetails nicely. You don't normally have the dependency injection working during test, since it usually requires booting a large chunk of code with a lot of configuration.
By adding a single private constructor, you avoid breaking encapsulation, but you can still inject your mock object into the code during test with a test framework like PowerMock. This is considered best practice.
You could break encapsulation and add publicly accessible methods or ctors to the SeviceClass, but if you don't need them for your design it's not good practice to add them only for test. That's why people put such effort into bypassing encapsulation in frameworks like Mockito and PowerMock. It's not just a dodge around private code, it's because you want to keep the encapsulation while still being able to test.
EDIT:
If you're not familiar with making mock objects, you should do some Google searches on the subject. It's very common and a good skill to have. With the above code, you could make your own mock object. But making mocks is so common that most test frameworks will do this for you.
For example, in PowerMock, I just looked at their page on making mocks here. You can make a mock like this
DAOInteface myMock = createMock(DAOInterface.class);
You can then ask the mock to verify that methods are called:
expect(myMock.someMethod());
Now the mock 'expects' that method to be called, and if it isn't, it'll generate an error for your test. Pretty sweet actually.
You can also return values from a call:
expect(myMock.insert()).andReturn("Test succeeded");
so your code would then see the value "Test succeeded" when it called that method. I don't see that 'insert' does return a value, that's just an example.

how to write unit test case for controller class using mockito

I am very new to Mockito and jUnit and I try to learn the right way to do TDD. I need couples of example so that i can write unit test using mockito
Following is my controller class which upload file and perform some action on this file inputs.
#Controller
#RequestMapping("/registration")
public class RegistrationController {
#Autowired
private RegistrationService RegistrationService;
#Value("#{Properties['uploadfile.location']}")
private String uploadFileLocation;
public RegistrationController() {
}
#RequestMapping(method = RequestMethod.GET)
public String getUploadForm(Model model) {
model.addAttribute(new Registration());
return "is/Registration";
}
#RequestMapping(method = RequestMethod.POST)
public String create(Registration registration, BindingResult result,ModelMap model)
throws NumberFormatException, Exception {
File uploadedFile = uploadFile(registration);
List<Registration> userDetails = new ArrayList<Registration>();
processUploadedFile(uploadedFile,userDetails);
model.addAttribute("userDetails", userDetails);
return "registration";
}
private File uploadFile(Registration registration) {
Date dt = new Date();
SimpleDateFormat format = new SimpleDateFormat("MM_dd_yyyy_HH_mm_ss");
File uploadedFile = new File(uploadFileLocation
+ registration.getFileData().getOriginalFilename() + "."
+ format.format(dt));
registration.getFileData().transferTo(uploadedFile);
return uploadedFile;
}
private void processUploadedFile(File uploadedFile, List<Registration> userDetails)
throws NumberFormatException, Exception {
registrationService.processFile(uploadedFile, userDetails);
}
}
can any body please suggest some example how can I write test case for this using mockito?
Edit
I have write down following test class but how to proceed further
#RunWith(MockitoJUnitRunner.class)
#ContextConfiguration(locations = { "/META-INF/spring/applicationContext.xml"})
public class BulkRegistrationControllerTest {
#InjectMocks
private RegistrationService registrationService= new RegistrationServiceImpl();
#Mock
private final ModelMap model=new ModelMap();
#InjectMocks
private ApplicationContext applicationContext;
private static MockHttpServletRequest request;
private static MockHttpServletResponse response;
private static RegistrationController registrationController;
#BeforeClass
public static void init() {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
registrationController = new RegistrationController();
}
public void testCreate()
{
final String target = "bulkRegistration";
BulkRegistration bulkRegistration=new BulkRegistration();
final BindingResult result=new BindingResult();
String nextPage=null;
nextPage = bulkRegistrationController.create(bulkRegistration, result, model);
assertEquals("Controller is not requesting the correct form",nextPage,
target);
}
}
There are a couple things you seem to have crossed up in your test. There are integration tests and unit tests. Integration tests will test everything (or almost everything) all hooked up - so you use Spring configuration files very close to the real ones and real examples of objects get injected to your class under test. That's mostly what I use #ContextConfiguration but I use that in conjunction with #RunWith(SpringJUnit4ClassRunner.class)
If you are using Mockito (or any mocking framework), it is usually because you want to isolate the class you are testing from real implementations of other classes. So instead of, for example, having to contrive a way to get your RegistrationService to throw a NumberFormatException to test that code path, you just tell the mock RegistrationService to do it. There are lots of other examples where it is more convenient to use mocks than to use real class instances.
So, that mini-lesson finished. Here is how I would re-write your test class (with an extra example and commented along the way).
#RunWith(MockitoJUnitRunner.class)
public class RegistrationControllerTest {
// Create an instance of what you are going to test.
// When using the #InjectMocks annotation, you must create the instance in
// the constructor or in the field declaration.
#InjectMocks
private RegistrationController controllerUT = new RegistrationController();
// The #Mock annotation creates the mock instance of the class and
// automatically injects into the object annotated with #InjectMocks (if
// possible).
#Mock
private RegistrationService registrationService;
// This #Mock annotation simply creates a mock instance. There is nowhere to
// inject it. Depending on the particular circumstance, it may be better or
// clearer to instantiate the mock explicitly in the test itself, but we're
// doing it here for illustration. Also, I don't know what your real class
// is like, but it may be more appropriate to just instantiate a real one
// than a mock one.
#Mock
private ModelMap model;
// Same as above
#Mock
private BulkRegistration bulkRegistration;
// Same as above
#Mock
private FileData fileData;
#Before
public void setUp() {
// We want to make sure that when we call getFileData(), it returns
// something non-null, so we return the mock of fileData.
when(bulkRegistration.getFileData()).thenReturn(fileData);
}
/**
* This test very narrowly tests the correct next page. That is why there is
* so little expectation setting on the mocks. If you want to test other
* things, such as behavior when you get an exception or having the expected
* filename, you would write other tests.
*/
#Test
public void testCreate() throws Exception {
final String target = "bulkRegistration";
// Here we create a default instance of BindingResult. You don't need to
// mock everything.
BindingResult result = new BindingResult();
String nextPage = null;
// Perform the action
nextPage = controllerUT.create(bulkRegistration, result, model);
// Assert the result. This test fails, but it's for the right reason -
// you expect "bulkRegistration", but you get "registration".
assertEquals("Controller is not requesting the correct form", nextPage,
target);
}
/**
* Here is a simple example to simulate an exception being thrown by one of
* the collaborators.
*
* #throws Exception
*/
#Test(expected = NumberFormatException.class)
public void testCreateWithNumberFormatException() throws Exception {
doThrow(new NumberFormatException()).when(registrationService)
.processFile(any(File.class), anyList());
BindingResult result = new BindingResult();
// Perform the action
controllerUT.create(bulkRegistration, result, model);
}
}
It's definitely possible to write pure unit tests for Spring MVC controllers by mocking their dependencies with Mockito (or JMock) as jherricks showed above. The challenge that remains is that with annotated POJO controllers there is a lot that remains untested -- essentially everything that's expressed in annotations and done by the framework when the controller is invoked.
Support for testing Spring MVC controllers is under way (see the spring-test-mvc project). While the project will still undergo changes it's usable in its present form. If you're sensitive to change however you should not depend on it. Either way I felt it was worth pointing out if you want to track it or participate in its development. There is a nightly snapshot and there will be a milestone release this month if you want to lock into a specific version.
The real question is:
How to set up an integration testing environment of your application which is using Spring?
The answer to this question is not simple, it really depends on how your web application works.
You should first focus on how to JUnit a Java web application, then on how to use Mockito.
Mockito is a mocking framework which is used to mock objects. This is usually feasible when you're testing a method which depends and on some other object's method result. For example, when testing your create method, you would want to mock the uploadedFile variable, as here you're not interested to test if the uploadFile(Registration registration) is working correctly(you test it in some other test), but you're interested to test if the method is processing the uploaded file and if it is adding the details in the model. To mock the upload file, you could go: when(RegistrationController.uploadFile(anyObject()).thenReturn(new File());
But then you see this shows a design issue. Your method uploadFile() should't reside in the Controller, but instead in some other utility class. And then you could #Mock that utility class instead of controller.
You have to remember that if your code is hard to test, that indicates you didn't do your best to keep it simple.
Looking at your code sample above I see a few issues:
The point of using Mockito is to mock the dependencies of your class. This will enable you to use a simple JUnit test case. Therefore there is no need to use #ContextConfiguration. You should be able to instantiate the class being tested using the new operator and then provide the required dependencies.
You're using Autowiring to provide your Registration service. In order to inject a mock instance of this service you will need to use the Spring testing private field access utilities.
I can't see from your code whether RegistrationService is an interface. If it's not you're going to have problems mocking it.
I am not familiar with Mockito (because I use JMock), but the general approach of writing tests with mocks is the same.
First you need an instance of the class under test (CUT) (RegistrationController). That must NOT be a mock - because you want to test it.
For testing getUploadForm the CUT-instance does not need any dependencies, so you can create it via new RegistrationController.
Then you should have a test hat looks a bit like this
RegistrationController controller = new RegistrationController();
Model model = new Model();
String result = controller(model);
assertEquals("is/Registration", result);
assertSomeContstrainsFormodel
That was easy.
The next method you want to test is create Method. That is much more difficult.
You need to have instance of the parameter objects (BindingResult) may be a bit more complicated
You need to handle the files in the test (delete them afterwards) - I will not discuss that problem. But may you should think of a way to use Temporary Files for the test instead.
You use the both variables registrationService and uploadFileLocation -- thats the interesting part.
uploadFileLocation is just a field that must be set in the test. The easyest way would be adding a (getter and) setter to set that filed in the test. You can also use the org.springframework.test.util.ReflectionTestUtils to set this field. -- both ways have pros and conns.
More interesting is registrationService. This should be a Mock! You need to create a Mock for that class, and then "inject" that mock in the CUT instance. Like for the uploadFileLocation you have at least the same two choices.
Then you need to define the exceptions you have for the mock: that registrationService.processFile(uploadedFile, userDetails) is invoked with the correct file and user details. (how exact this exception is defined is part of Mockito - and I have not enough knowlege).
Then you need to invoke the method you want to test on CUT.
BTW: If you need to "inject" mocks on Spring beans very often, then you can build your own util. That get an instance of an object, scan that object for fields with #Inject annotations, create Mocks for that and "inject" that mocks. (Then you only need getter to access the mocks to define there expections.) -- I have build such an tool for JMock, and it helped me a lot.
Alternative suggestion: don't use Mockito. Spring comes with its own testing classes that you can use to mock, and you can use the SpringJUnit4ClassRunner. Using the Spring JUnit test runner allows you to load a full Spring configuration (via #ContextConfiguration) as well as to mock objects. In your case, much of your instantiation code goes away, because you will be running Spring, not mimicking its DI.
Try this.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "/META-INF/spring/applicationContext.xml"})
public class BulkRegistrationControllerTest {
#Mock
private RegistrationService registrationService;
//Controller that is being tested.
#Autowired
#InjectMocks
private RegistrationController registrationController;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
...
}
...

Categories