I am new to jmock and trying to mock an HttpSession. I am getting:
java.lang.AssertionError: unexpected invocation: httpServletRequest.getSession()
no expectations specified: did you...
- forget to start an expectation with a cardinality clause?
- call a mocked method to specify the parameter of an expectation?
the test method:
#Test
public void testDoAuthorization(){
final HttpServletRequest request = context.mock(HttpServletRequest.class);
final HttpSession session = request.getSession();
context.checking(new Expectations(){{
one(request).getSession(true); will(returnValue(session));
}});
assertTrue(dwnLoadCel.doAuthorization(session));
}
I have done a bit of searching and it isn't clear to me still how this is done. Feels like I am missing some small piece. Anyone with experience in this can just point me in the right direction.
thanks
You don't need to mock the request object. Since the method you're testing (dwnLoadCel.doAuthorization()) only depends on an HttpSession object, that is what you should mock. So your code would look like this:
public void testDoAuthorization(){
final HttpSession session = context.mock(HttpSession.class);
context.checking(new Expectations(){{
// ???
}});
assertTrue(dwnLoadCel.doAuthorization(session));
}
The question becomes: what do you expect the SUT to actually do with the session object? You need to express in your expectations the calls to session and their corresponding return values that are supposed to result in doAuthorization returning true.
I think you need to tell the JMock context how many times you expect the method to be called before you actually go ahead and call it.
final HttpServletRequest request = context.mock(HttpServletRequest.class);
context.checking(new Expectations(){{
one(request).getSession(true); will(returnValue(session));
}});
final HttpSession session = request.getSession();
I'm not super familiar with JMock but do you actually care in your dwnLoadCel unit test how many times certain methods in the mocked object are called? Or are you just trying to test your class that depends on a HttpSession without an actual Session? If it's the latter than I think that JMock is overkill for you.
You might want to look into either creating a class that implements the HttpSession interface yourself for the purposes of unit testing only (a stub), and running your tests off of that, or you should take a look at dwnLoadCel and determine if it really needs to have a reference to the HttpSession, or if it just needs some properties within the HttpSession. Refactor dwnLoadCel to only depend on what it actually needs (a Map or a certain parameter value within the Session object) - this will make your unit test easier (the dependency on the servlet container goes bye-bye).
I think that you have some level of dependency injection in your class being tested already, but you might be dependent on too broad of an object. The Google Test Blog has had a lot of excellent articles on DI lately that you might find useful (I sure have).
Related
I am trying to write a unit test for a GWT Servlet.
Therefore i need to mock the getThreadLocalRequest() function of AbstractRemoteServiceServlet so that i dont get NPE's.
The function is protected so according to the mocktio faq it should be possible to mock it as long as I am inside the same package.
So I tried the following:
HttpServletRequest request = mock(HttpServletRequest.class);
svc = spy(new GreetingServiceImpl());
doReturn(request).when(svc).getThreadLocalRequest();
But I get the following error that the function isnt visible:
The method `getThreadLocalRequest()` from the type `AbstractRemoteServiceServlet` is not visible
I would appreciate any advices on the problem or hints on a better solution of my problem.
Mockito can't modify the java rules for visibility and the return value of when(svc) isn't in a package where getThreadLocalRequest() is visible.
Make sure that your test class is in the same package as AbstractRemoteServiceServlet or call the getThreadLocalRequest method is via reflection:
Method getThreadLocalRequestMethod = AbstractRemoteServiceServlet.class.getDeclaredMethod("getThreadLocalRequest");
Object target = doReturn(request).when(svc);
Object regetThreadLocalRequestMethod.invoke(target);
I really need your help. I'm using my portlet app as usual when suddenly I have to get out of computer. When I return, there's NullPointerException. OK, why's that? Hmm... my session doesn't contain object it should hold. So, I'm probably loosing something but here's how I always looked at SessionAttributes.
I have my Controller annotated as so:
#SessionAttributes({
SOME_ATTR
})
Then I have a method with following signature:
#Valid #ModelAttribute(SOME_ATTR) SomeObject someObject
And also init method for my session attribute:
#ModelAttribute(SOME_ATTR)
public SomeObject getSomeEmptyObject() {
return someUtils.createSomeObject();
}
When I debugged my app at this point I found out that:
manually looking into the session, there's nothing in it
form is properly binded to someObject
So my two big questions are:
why doesn't Spring set someObject into session as well?
when the session was invalidated, why wasn't getSomeEmptyObject() called to fill the empty space?
Thanks in forward!
Have a look at HttpSessionBindingListener and the HttpSessionAttributeListener. If SomeObject is a class that you control, you can implement HttpSessionBindingListener otherwise you will likely need HttpSessionAttributeListener.
This SO posting covers this pretty well.
Well, do you set your session attribute in proper form:
#SessionAttributes(value = {"user", "register"})
Thats all that I can think about.
I am admittedly new to JMockit, but I am for some reason having trouble mocking System.getProperties(). Thanks to the help of following post:
https://stackoverflow.com/questions/25664270/how-can-i-partially-mock-the-system-class-with-jmockit-1-8?lq=1
I can successfully mock System.getProperty() using JMockit 1.12:
#Test
public void testAddSystemProperty_String() {
final String propertyName = "foo";
final String propertyValue = "bar";
new Expectations(System.class) {{
System.getProperty(propertyName);
returns(propertyValue);
}};
assertEquals(propertyValue, System.getProperty(propertyName));
}
But the eerily similar code for mocking getProperties() barfs:
#Test
public void testAddSystemProperty_String() {
final String propertyName = "foo";
final String propertyValue = "bar";
final Properties properties = new Properties();
properties.setProperty(propertyName, propertyValue);
new Expectations(System.class) {{
System.getProperties();
returns(properties);
}};
assertEquals(1, System.getProperties().size());
}
I get the following exception that points to the "returns" method:
Missing invocation to mocked type at this point;
please make sure such invocations appear only after
the declaration of a suitable mock field or parameter
Also, how do I mock both methods at the same time? If I put them in the same Expectations block (with the getProperty() first), then I do not see the exception, but System.getProperties() returns the real system properties, not the mocked ones; though getProperty(propertyName) returns the mocked value. I find that totally wonky behavior.
I see from this post that certain methods cannot be mocked, but System.getProperties() is not on that list:
JMockit NullPointerException on Exceptions block?
I am also finding that a lot of solutions on SO that worked with JMockit 2-3 years ago are totally non-compilable now, so apparently things change a lot.
System.getProperties() is indeed one of the methods excluded from mocking in JMockit 1.12. The exact set of such excluded methods can change in newer versions, as new problematic JRE methods are found.
There is no need to mock System.getProperty(...) or System.getProperties(), though. The System class provides setProperty and setProperties methods which can be used instead.
Hopefully someone else finds this useful:
This can be solved with Mockito / PowerMock (1.5.3).
Note that I am testing a utility that will exhaustively try to find the property value given a list of possible sources. A source could be a system property, an environment variable, a meta-inf services file, a jndi name, a thread local, a file on disk, an ldap, basically anything that can perform a lookup.
#RunWith(PowerMockRunner.class)
#PrepareForTest({ClassThatDirectlyCallsSystemInCaseItIsNestedLikeInMyCase.class})
public class ConfigPropertyBuilderTest {
#Test
public void testAddSystemProperty_String_using_PowerMockito() {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getProperty(propertyName)).thenReturn(propertyValue);
PowerMockito.when(System.getProperties()).thenReturn(new Properties() {{
setProperty(propertyName, propertyValue);
}});
// Here is realistic case of calling something that eventually calls System
// new configBuilder().addEnvironmentVariable(propertyName)
// .addSystemProperty(propertyName)
// .getValue();
// Here is simplified case:
assertEquals(1, System.getProperties().size());
assertEquals(propertyValue, System.getProperty(propertyName));
}
}
I could call System.setProperty(), but when you start getting into the other sources, it becomes less clear.
Note that I do not specifically care about the value returned by System.getProperty() either; I simply want to ensure that it is called if the first look up fails.
For example, in the above code snippet, the environment variable does not exist, so System.getProperty() should be called. If the environment variable existed (as it does in the next test case which is not shown), then I want to verify that System.getProperty() was not called because it should have short circuited.
Because of the difficulties in faking out the other sources using real files, real ldap, real APIs, etc, and because I want to verify certain APIs are either called or not called, and because I want to keep the tests looking consistent, I think mocking is the correct methodology (even though I may be trying to mock stuff that is not recommended in order to keep it all looking consistent). Please let me know if you think otherwise.
Also, while I do not understand the difficulties of maintaining these mocking frameworks (especially the cglib based ones), I understand the difficulties do exist and I can appreciate the sort of problems you face. My hat goes off to you all.
I have an application with a class registered as a message listener that receives messages from a queue, checks it's of the correct class type (in public void onMessage(Message message)) and sends it to another class that converts this class to a string and writes the line to a log file (in public void handleMessage(MessageType m)). How would you write unit tests for this?
If you can use Mockito in combination with JUnit your test could look like this:
public void onMessage_Success() throws Excepton {
// Arrange
Message message = aMessage().withContent("...").create();
File mockLogFile = mock(File.class);
MessageHandler mockMessageHandler = mock(MessageHandler.class);
when(mockMessageHandler).handleMessage(any(MessageType.class)
.thenReturn("somePredefinedTestOutput");
when(mockMessageHandler).getLogFile().thenReturn(mockLogFile);
MessageListener sut = spy(new MessageListener());
Whitebox.setInternalState(sut, "messageHanlder", mockMessageHandler);
// or simply sut.setMessageHandler(mockMessageHandler); if a setter exists
// Act
sut.onMessage(message);
// Assert
assertThat(mockLogFile, contains("your desired content"));
verify(sut, times(1)).handleMessage(any(Message.class));
}
Note that this is just a simple example how you could test this. There are probably plenty of other ways to test the functionality. The example above showcaeses a typical builder-pattern for the generation of default-messages which accept certain values for testing. Moreover, I have not really clarified the Hamcrest matcher for the contains method on the mockLogFile.
As #Keppil also mentioned in his comment, it makes sense to create multiple test-cases which varry slightly in the arrange and assert parts where the bad-cases are tested
What I probably didn't explain enough is that getLogFile() method (which with high certainty has an other name in your application) of MessageHandler should return the reference to the file used by your MessageHandler instance to store the actual log-messages. Therefore, it probably is better to define this mockMessageHandler as spy(new MessageHandler()) instead of mock(MessageHandler.class) although this means that the unit-test is actually an integration test as the interaction of two classes is tested at the same time.
But overall, I hope you got the idea - use mock(Class) to generate default implementations for dependencies your system-under-test (SUT) requires or spy(Instance) if you want to include a real-world object instead of one that only has null-values as return types. You can take influence on the return-value of mocked objects with when(...).thenReturn(...)/.thenThrow(...) or doReturn(...).when(...) in case of void-operations f.e.
If you have dependency-injection into private fields in place you should use Whitebox.setInternalState(...) to inject the values into the sut or mock classes if no public or package-private (if you obtain the testing-model of reusing the package structure of the system-under-test classes within your test-classes) setter-methods are available.
Further, verify(...) lets you verify that a certain method was invoked while executing the SUT. This is quite handy in this scenario when the actual assertion isn't that trivial.
I want to use mockito spy.
When I set a return value in both following ways:
when(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user)).thenReturn(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user, fakeNowDate));
doReturn(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user, fakeNowDate)).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
I see the return value is being evaluated eagerly
meaning when this "setting" line is executed.
how can i force the spy to evaluate the return value only on demand?
meaning when the "when" condition is met.
update
Thanks to #RobbyCornelissen I have tried this code:
when(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user)).thenAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
ImagesSorter mock = (ImagesSorter)invocation.getMock();
return mock.sortImages((List<Image>)args[0], (UserInfo)args[1], fakeNowDate);
}
});
But it didn't help:
1) the "when" expression was invoked immediately. (not wanted)
2) eventually the callback wasn't call.
First let me warn you on partial mocks, because that is what the code is actually doing, it's wrong design wise. It may be more relevant to use a strategy pattern to compose behavior of the tested subject. Mockito team (including me) strongly advises to stay away of partial mocks whenever possible.
EDIT : I don't know the code and I don't know exactly which component under test but from what I gather there's a type responsible to sort images, let's call it ImagesSorter.
So first case ImagesSorter is a dependency of a test subject, so in this case just stubbing the mock of ImagesSorter will do.
If however it is ImagesSorter itself under test, and stubbing a special method of this class is called a partial mock and it is plain wrong. It exposes internal of the production code in the test. So there's several solutions.
As the code snippet showed in the answer shows a fakeDate, one of the solution is to not use things like new Date() and code a simple class TimeSource whose sole responsibility is to provide a date. And in tests the bwhavior of this TimeSOurce could be overriden.
A simplier solution would be to use JodaTime as it provides this functionality built in.
If the scope of test goes beyond changing the date, then maybe ImagesSorter needs a way to be configured with other objects. Inspiration on how to do it can be found with the cache builder of guava. If the configuration is dead simple then a simple constructor coud do it.
That could look like :
class ImagesSorter {
ImagesSorterAlso algo;
ImagesSorter(ImagesSorterAlgo algo) { this.algo = algo; }
Iterable sortImages(...) {
algo.sort(...);
}
}
interface ImagesSorterAlgo {
Iterable sort(...);
}
Now about your questions :
1) the "when" expression was invoked immediately. (not wanted)
It is expected imagesSorterSpy is a spy so by default it calls the real code. Instead you should use the alternate API, the same that #RobbyCornelissen showed. i.e.
doAnswer(sortWithFakeDate()).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
// with BDD aliases (BDDMockito) which I personnaly finds better
willAnswer(sortWithFakeDate()).given(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
will(sortWithFakeDate()).given(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
sortWithFakeDate() would a static factory method that returns the answer, so the code reads well, and maybe reused elsewhere.
2) eventually the callback wasn't call.
This issue is most probably due to non equal arguments. You may need to check the equals method. Or relax the stub using the any() matcher.
I don't know the types of the arguments and classes you're using, so I can't provide a complete example, but you can stub using callbacks with the Answer<T> interface:
Mockito.doAnswer(new Answer() {
Object answer(InvocationOnMock invocation) {
ImagesSorter mock = (ImagesSorter) invocation.getMock();
Object[] args = invocation.getArguments();
return mock.sortImages((List<Image>) args[0], (UserInfo) args[1],
fakeNowDate);
}
}).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);