Unexpected method call while doing the unit testing with EasyMock - java

I am testing mail functionality in my code with the UnitilsJUnit4 and EasyMock.
My code is like this..
public void prepare(MimeMessage mimeMessage) {
// some code ..
MimeMessageHelper message = new MimeMessageHelper( mimeMessage, true );
// some mail settings ..
}
when I am testing the method prepare, it is giving the below exception.. but the method it is showing below is from the Spring framework class.
java.lang.AssertionError:
Unexpected method call setContent(javax.mail.internet.MimeMultipart#6e616e61):
setContent(javax.mail.internet.MimeMultipart#2dda2dda): expected: 1, actual: 0
at $javax.mail.internet.MimeMessage$$EnhancerByCGLIB$$614de43f.setContent(<generated>)
at org.springframework.mail.javamail.MimeMessageHelper.createMimeMultiparts(MimeMessageHelper.java:344)
at org.springframework.mail.javamail.MimeMessageHelper.<init>(MimeMessageHelper.java:290)
at org.springframework.mail.javamail.MimeMessageHelper.<init>(MimeMessageHelper.java:247)
at org.springframework.mail.javamail.MimeMessageHelper.<init>(MimeMessageHelper.java:226)
Please help me to resolve the above issue.. how to test my method?

I know this was written a long time ago, but I just encountered this exact same problem.
If you can mock the MimeMessageHelper in some form you can easily test the code. I did this by creating an interface that simply supplies back the MimeMessageHelper class and adding that as a dependency to the class I was testing.
Interface:
public interface MimeMessageHelperProvider {
MimeMessageHelper getMimeMessageHelper(MimeMessage mimeMessage);
}
Implementation:
public class MimeMessageHelperProviderImpl implements MimeMessageHelperProvider {
#Override
public MimeMessageHelper getMimeMessageHelper(MimeMessage mimeMessage) {
return new MimeMessageHelper(mimeMessage);
}
}
Now you can wire in the MimeMessageHelperProvider and simply mock that interface to have it return you an instance you can verify against.

You seem to be mocking the wrong thing. You're mocking the Mail API when you should be mocking the Spring class, since that's what you interact with directly. The way you're doing it now, you're effectively testing the Spring class along with your own, which isn't really what you want.

You need to mock the MimeMessageHelper. You can't inject it because it takes mimeMessage in the constructor. So to do this you need something like PowerMock.
From the documentation:
Use the #RunWith(PowerMockRunner.class) annotation at the
class-level of the test case.
Use the #PrepareForTest(ClassThatCreatesTheNewInstance.class)
annotation at
the class-level of the test case.
Use
PowerMock.createMock(NewInstanceClass.class) to create a mock
object
of the class that should be constructed (let's call it
mockObject).
Use
PowerMock.expectNew(NewInstanceClass.class).andReturn(mockObject)
to
expect a new construction of an object of type
NewInstanceClass.class but instead return the mock object.
Use
PowerMock.replay(mockObject, NewInstanceClass.class) to change the
mock object and class to replay mode, alternatively use the
PowerMock.replayAll() method.
Use PowerMock.verify(mockObject,
NewInstanceClass.class) to change the mock object and class to
verify mode, alternatively use the PowerMock.verifyAll() method.
Obviously, I don't really know what you're trying to test, but your test would look something like:
#RunWith(PowerMockRunner.class)
#PrepareForTest(MessagePreparer.class)
public class MessagePreparerTest {
#Test
public void testPrepare() {
MimeMessage mockMessage = PowerMock.createMock(MimeMessage.class);
MimeMessageHelper mockMessageHelper = PowerMock.createMock(MimeMessageHelper.class);
PowerMock.expectNew(MimeMessageHelper.class,
mockMessage, true).andReturn(mockMessageHelper);
// ...set other expectations
PowerMock.replay(mockMessage, mockMessageHelper, MimeMessageHelper.class);
MessagePreparer messagePreparer = new MessagePreparer();
messagePreparer.prepare(mockMessage);
PowerMock.verify(mockMessage, mockMessageHelper, MimeMessageHelper.class);
}
}

Related

Mock an object which is not injected

I'm new to Java programming and I have the following code:
import javax.ws.rs.client.ClientBuilder;
public class Foo {
private final Client http;
Foo() {
http = ClientBuilder.newClient().register(CurlRequestFactory.getCurlRequestFactory().get(LOGGER, “someString”));
}
public someMethod() {
Invocation.Builder request = http.target(getURI(“someUri”)).request().header(“someHeader”, “someValue”);
Response response = request.get();
}
}
I want to write a unit test for someMethod() where request.get() would throw an exception. For this I require that request object should be set as a mock object.
But I'm unable to do so as it is being initialized directly instead of getting injected.
I know I can mock an object if it was getting injected as below:
Response responseMock = Mockito.mock(Response.class);
Mockito.when(responseMock.get()).thenThrow(new Exception("someMessage"));
But I couldn't find anything which works for my scenario.
PS: I don't want to use Powermock.
I have come across few things that Mokito does not support. One is this scenario. Either you have to change your code to inject it or use PowerMockito. I don't think there is any other option.
Your method is probably doing too many things. I imagine that you don't want to just return the Response from someMethod. Refactor your code to someMethod(Response response) or even better someMethod(Pojo responseBody) and then test that.
I don't know what your use case is, but someMethod probably belongs to another class (I'll call it Bar) separate from the http client class (Foo). You can then inject Foo into Bar and do the test. Is there any reason why you wouldn't want to refactor to that?

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.

Mock constructor with mockito

I want to mock a constructor into method.
public String generaID() {
GeneraIDParaEntidadCliente aux = new GeneraIDParaEntidadCliente(nombre, registro);
entidad.setID(aux.generaID);
}
In my test I want do something like this :
when(new GeneraIDParaEntidadCliente(anyString(), any(Entidad.class)).thenReturn(generaIdMock)
but give me this error org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Any idea why?
UPDATE: since since version 3.5.0, Mockito can do this without PowerMockito.
You can use PowerMock to mock constructors.
If you can't use PowerMock for some reason, the most workable solution is to inject a factory to whatever class contains this method. You would then use the factory to create your GeneraIDParaEntidadCliente object and mock the factory.
There are a couple of ways of doing this, described in my article on the Mockito wiki
Copying answer from duplicate:
Mockito can now mock constructors (since version 3.5.0) https://javadoc.io/static/org.mockito/mockito-core/3.5.13/org/mockito/Mockito.html#mocked_construction
try (MockedConstruction mocked = mockConstruction(Foo.class)) {
Foo foo = new Foo();
when(foo.method()).thenReturn("bar");
assertEquals("bar", foo.method());
verify(foo).method();
}
you can send mocked objects as paramemters to your class constructor, form example:
// define you object
public MainClassObj instanceClass;
// mock input parameter
MYClassObj mockedObj = Mockito.mock(MYClassObj.class);
// call construvtor with mocked parameter
instanceClass = new instanceClass(mockedObj);

Mockito: How to get the state of an argument

The scenario is I am trying to validate a domain object and store the validation messages in another object. The class is Validator and the method looks like:
public void validate (Domain domain, ValidationInfo info)
And the ValidationInfo object has:
List<String> messages = new ArrayList<String> messages ()
The Validator class is called from a service class. Whatever validation fails for the domain object the failure messages will be stored in the list in the ValidationInfo class.
In the service test class in one of the test case i wrote the following to test the validation failure:
#Test
public void testvalidation () throws Exception {
Domain domain = createDomainWithInvalidData();
service.create (domain);
verify(mockValidator).validate(domain, validationInfo);
assertFalse (validationInfo.getMessages().isEmpty());
Now What I want is to get the failure messages from the validationInfo object so that I can write some asserts based on that. But it's not working.
Can anybody shed some light on this.
From what I gather you are unit testing the service.
Actually there's is no point in getting the messages from validationInfo as it is passed to a method of Mockito mock which does nothing by definition unless you write a stub (given(...).willReturn(...)). Even the last assertion in your code sample is not necessary as validationInfo won't be modified by the default mocked behavior of validate.
Mockito is designed and lead to test interactions between collaborators, which is already done with your verification verify(...), as you are testing the service and his collaboration with the Validator.
Testing the message that was written in ValidationInfo has nothing to do with the scope of service
However what you want is to unit test the Validator, in which you should write specific tests for validation messages. Look at the following snippet where I imaginated some part of the ValidationInfo API :
public class ValidatorTest {
Validator validator = new Validator(); // not a mock
#Test
public void when_<some_part_of_the_domain>_is_incorrect_report_validation_error() throws Exception {
// given
Domain domain = createDomainWithInvalidData();
// when
validator.validate(domain, validationInfo);
// then
assertThat(validationInfo.getMessages()).isNotEmpty()); // not really necessary
assertThat(validationInfo.getLastMessage().text()).contains("<some_part_of_the_domain> is wrong");
}
}
Note that I used the BDD keywords (given, when, then) to help me write the test. Alos I used FestAssert library which affer great assertion tools.
Hoep that helps.
I was able to achieve what i wanted after breaking my head for hours.
What we need to do is use doAnswer of mockito. Please find below the snippet:
doAnswer(new Answer<ValidationInfo> () {
#Override
public ValidationInfo answer (InvocationOnMock invocationOnMock) throws Throwable {
Object [] args = invocationOnMock.getArguments();
ValidationInfo vi = (ValidationInfo) args [1];
vi.getMessages.add("some message");
return vi;
}}).when(validator).validate (domain, validationInfo);
This way I was able to put custom failure messages in the list which made the validation fail in the service; which was the whole purpose of the test.
And earlier the test was not passing because in the service code there was a check on the size of the list. And the list size was always zero as verify will just verify whether the method gets called or not but wont actually change the state of the object.
Hope this helps. If there is any better way of achieving this please comment.

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