I'm trying to mock a class that looks like below
public class MessageContainer {
private final MessageChain[] messages;
MessageContainer(final int numOfMessages, final MessageManagerImpl manager, final Object someOtherStuff) {
messages = new MessageChain[numOfMessages]
// do other stuff
}
public void foo(final int index) {
// do something
messages[index] = getActiveMessage();
}
}
My test code would be as followed:
#Test
public void testFoo() {
MessageContainer messageContainer = Mockito.mock(MessageContainer.class);
Mockito.doCallRealMethod().when(messageContainer).foo(anyIndex);
}
I got a NullPointerException since 'messages' is null. I tried to inject the mock by using #InjectMocks, however this case is not supported since not every parameters of the constructor are declared as members.
I also tried to set the 'messages' field by using WhiteBox
Whitebox.setInternalState(messageContainer, MessageChain[].class, PowerMockito.mock(MessageChain[].class));
but I got a compile error since setInternalState only supports (Object, Object, Object) and not Object[].
Is there any possible way to mock a private final field?
Thank you guys in advance.
Based on your edits and comments, I would say mocking this class and verifying the method was invoked is sufficient.
If it is third-party code, you should rely only on its method signature, which comprises the class's public API. Otherwise you are coupling your tests too tightly to something you have no control over. What do you do when they decide to use a Collection instead of an array?
Simply write:
MessageContainer container = mock(MessageContainer.class);
//Your code here...
verify(container).foo(obj);
Related
I'm learning about unit testing and I came across the problem to create a final check on wether a test case is correct or not. Usually I try to create a verification, like through an assertEquals(). But what is recommended to do when it's not possible to test it like this?
I have a class like this:
public class Landlord {
private Map<String, ChannelHandlerContext> currentOccupier;
private static Landlord instance;
public Landlord() {
currentOccupier = new HashMap<>();
}
public static Landlord getInstance {
//return instance
}
public void add(Occupier occupier){
currentOccupier.put("test", occupier.getChannelHandlerContext());
}
}
And now I try to test the method like this:
public class LandlordTest {
private Landlord landlord;
#Mock
private Occupier occupier;
#Mock
private ChannelHandlerContext channelHandlerContext;
#BeforeEach
void setUp() {
occupier = mock(Occupier.class);
channelHandlerContext = mock(ChannelHandlerContext.class);
landlord = Landlord.getInstance();
when(occupier.getChannelHandlerContext()).thenReturn(channelHandlerContext);
}
public void add(Occupier occupier){
addedOccupier.put(occupier.getChannelHandlerContext());
//adding succeded
}
}
Maybe in this short example it wouldn't be needed to test it, but is there a way to verify that the add method was successful? Normally in these kind of cases, I'd try something like: assertEquals(currentOccupier.size(), 1), but here I can't access the hashMap of the instance to do it like this. Is there another way to verify the correct behaviour of adding it?
This assertEquals(currentOccupier.size(), 1) is really not enough.
You want to assert that the map contains the entry that you added in the map.
That assertion is too shallow : it doesn't check for the entry neither the value of the key nor the value of the value.
You should do something like :
ChannelHandlerContext actualContext = landLord.get("test");
assertSame(addedContext, actualContext);
// or assertEquals if the instances may differ because you do some defensive copy in add()
Note also that you mock here some things that should not need to be mocked : occupier and channelHandlerContext make part of your model. You should be able to provide "normal" instances of them in the frame of the test.
Here you have broadly two ways to perform that :
1) adding a public method in the class to under test to find an ChannelHandlerContext :
public ChannelHandlerContext get(String name){
currentOccupier.get(name);
}
Do that only if providing this access is acceptable.
If you cannot add a public method, add a package level method as this doesn't make part of the exposed API.
2) use reflection api (essentially Class.getDeclaredField(String) and Field.get()) to retrieve the map instance from the instance under test and then assert that it contains the expected ChannelHandlerContext instance for the "test" key.
I'd like to do this mocking with Mockito
MyServiceClass
(this isn't the actual code, just a fake example with a similar intent)
public String getClassObjects() {
OtherClassObject otherclass = OtherClassObject.createOtherClassObject();
String id = otherclass.getParentObject().getId();
return id;
}
So essentially I want to mock ".getId()" but only in the context of this class "MyServiceClass" if I call the same method of "getId()" in a different class I want to be able to mock a different return.
This will return "3" in every method call for the OtherClassObject
new MockUp<MyServiceClass>() {
#Mock
public String getId(){
return "3";
}
};
Is there a way to isolate method calls for a class object within the scope of a specific class?
Plain Mockito is unable to mock static calls, so you need PowerMock here. To achieve desired you should return different values from the mocked object like this
// from your example it's not clear the returned type from getParentObject method.
// I'll call it ParentObj during this example. Replace with actual type.
ParentObj poOne = mock(ParentObj.class);
when(poOne.getId()).thenReturn("3");
ParentObj poTwo = mock(ParentObj.class);
when(poTwo.getId()).thenReturn("10");
...
OtherClassObject otherClassObjectMock = mock(OtherClassObject.class);
// return all your stubbed instances in order
when(otherClassObjectMock.getParentObject()).thenReturn(poOne, poTwo);
PowerMockito.mockStatic(OtherClassObject.class);
when(OtherClassObject.createOtherClassObject()).thenReturn(otherClassObjectMock);
Thus, you can customize your mocks per needs, specifying desired return value, or propagating call to actual (real) method.
Don't forget to use annotations #RunWith(PowerMockRunner.class) and #PrepareForTest(OtherClassObject.class) on class level to activate the magic of PowerMock.
An alternative idea is to get rid of static call inside your getClassObjects method and pass factory using constructor, so you can easily mock it, setting mocked object only for single class.
Hope it helps!
I'm trying to mock the following class which contains some static members
public class ClientFact {
private static final String BASE_URL = Config.getProperty("prop1");
private static final String USERID = Config.getProperty("prop2");
......................
public static Client createClient() throws AppException {
}
}
but i'm running into issues with the static member variables which are populated by Config.getProperty. This class does a read on a properties file like so
public class Config {
...............
public static String getProperty(Param param) {
String value = null;
if (param != null) {
value = properties.getProperty(param.toString());
}
return value;
}
}
I'm trying to mock this call since i dont care about the loaded properties in my test. This is what ive tried
#RunWith(PowerMockRunner.class)
#PrepareForTest({ClientFact.class})
public class MyTests {
#Test
public void test() {
PowerMock.mockStaticPartial(Config.class, "getProperty");
EasyMock.expect(Config.getProperty(EasyMock.anyObject())).andReturn(EasyMock.anyString()).anyTimes();
PowerMock.mockStatic(ClientFact.class);
}
}
but its giving the following error...
java.lang.NoSuchMethodError: org/easymock/internal/MocksControl.createMock(Ljava/lang/Class;[Ljava/lang/reflect/Method;)Ljava/lang/Object;
at org.powermock.api.easymock.PowerMock.doCreateMock(PowerMock.java:2214)
at org.powermock.api.easymock.PowerMock.doMock(PowerMock.java:2163)
any ideas what im doign wrong here?
A non-answer: consider not making static calls there.
You see, that directly couples that one class to the implementation of that static method in some other class; for no real reason. (and for the record: it seems strange that a USER_ID String is a static field in your ClientFact class. Do you really intend that all ClientFacts are using the same USER_ID?!)
You could replace that static call with a non-static version (for example by introducing an interface); and then you can use dependency injection to make an instance of that interface available to your class under test. And then all your testing works without the need to Powermock.
Long story short: very often (but not always!) the need to turn to Powermock originates in production code which wasn't written to be testable (like in your case). Thus instead of using the big bad Powermock hammer to "fix" your testing problem, you should consider improving your production code.
You might want to listen to those videos to get a better understanding what I am talking about.
I write simple application. I don't want to use any frameworks. Please suggest me right place to hold annotation processing.
I have a few lines in main method:
String myString = (#NonNull String)list;
And I created #interface:
#Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
public #interface NonNull {
}
Which step should I take next? Can I work with annotations without using reflection? Could you expose for me samples of such annotation processing code?
There is no way (AFAIK) to work with annotations without reflection.
If you don't want to use any framework, first step is to write kind of proxy class handling the method requests. It is an example of method processing with annotation use over method:
public class MyProxy {
private <T> T getProxy(T t) {
return (T) Proxy.newProxyInstance(t.getClass().getClassLoader(), new Class<?>[]{MyClass.class}, new MyInvocationHandler(t));
}
}
And then implement InvocationHandler:
public class MyInvocationHandler implements InvocationHandler {
private Object obj;
MyInvocationHandler (Object obj) {
this.obj = obj;
}
#Override
public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
boolean isNotNull = method.isAnnotationPresent(NotNull.class);
if (isNotNull) {
/* process annotated method. Or go through proxy object fields etc.. */
}
}
}
I hope it will help you.
You didn't say what kind of annotation processing you want to do.
Do you want to add a run-time check that will cause your code to crash if list is ever null at run time? For this, reflection will work.
Do you want to add a compile-time check that will reject your code if it cannot prove that list is never null at run time? For this, an annotation processor such as the Checker Framework will work.
Your question does not explain why you don't want to use a framework. Doing so will save you from re-implementing a lot of functionality that others have already created.
It looks like EasyMock version 3.2 now supports using annotations to setup mock objects. I am new to EasyMock (and Java in general) and am trying to understand how to use this. Do these annotations do something new or just provide an alternative way to do things? The documentation says:
Since EasyMock 3.2, it is now possible to create mocks using annotations. This is a nice
and shorter way to create your mocks and inject them to the tested class.
Here is the example above, now using annotations: ...
Then there is a listing that shows use of the #TestSubject and #Mock annotations, but I don't understand how it works. It seems as if it magically sets the private field of the class under test to the mock object. In most of my cases, I just want to make mock objects that return pre-defined values for use in JUnit test cases (don't currently care about verifying which ones were called, how many times they were called, etc). For example, for some tests I want to create a fake HttpServletRequest object like this:
public class SomeTest {
// Construct mock object for typical HTTP request for the URL below
private static final String REQUEST_URL = "http://www.example.com/path/to/file?query=1&b=2#some-fragment";
private static final Map<String, String> requestHeaderMap;
static {
Map<String, String> requestHeaders = new LinkedHashMap<String, String>();
requestHeaders.put("host", "www.example.com");
// ... (add any other desired headers here) ...
requestHeaderMap = Collections.unmodifiableMap(requestHeaders);
}
private HttpServletRequest httpServletRequest;
// ...
#Before
public void setUp() throws Exception {
httpServletRequest = createNiceMock(HttpServletRequest.class);
expect(httpServletRequest.getRequestURI()).andReturn(REQUEST_URL).anyTimes();
expect(httpServletRequest.getHeaderNames()).andReturn(Collections.enumeration(requestHeaderMap.keySet())).anyTimes();
capturedString = new Capture<String>();
expect(httpServletRequest.getHeader(capture(capturedString))).andAnswer(new IAnswer<String>() {
public String answer() throws Throwable {
String headerName = capturedString.getValue().toLowerCase();
if (requestHeaderMap.containsKey(headerName))
return requestHeaderMap.get(headerName);
else
return "";
}
}).anyTimes();
replay(httpServletRequest);
// ...
}
#Test
public void someMethod_givenAnHttpServletRequest_shouldDoSomething() {
// ...
}
}
Could I change the above code to use annotations? If so, should I? Under what circumstances?
I thought perhaps putting the #Mock annotation above an instance variable declaration would automatically take care of the createNiceMock(...) part, but this does not seem to work, so I suspect that I am misunderstanding something.
Examining their source code, they are using reflection to inject anything with an #Mock into a field of the #TestSubject. Their javadoc for the method
public static void injectMocks(final Object obj)
in EasyMockSupport.java says:
Inject a mock to every fields annotated with {#link Mock} on the class passed in parameter. Then, inject these mocks to the fields of every class annotated with TestSubject.
The rules are
Static and final fields are ignored
If a mock can be assigned to a field, do it. The same mock an be assigned more than once
If no mock can be assigned to a field, skip it silently
If two mocks can be assigned to the same field, return an error
Fields are searched recursively on the superclasses
Note: If the parameter extends EasyMockSupport, the mocks will be created using it to allow replayAll/verifyAll to work afterwards
#param obj the object on which to inject mocks
#since 3.2
public static void injectMocks(final Object obj) {
...
}
For you to use the #Mock annotation, you would need a #TestSubject that has an HttpServletRequest field for EasyMock to set the #Mock on (via reflection). The annotations are provided to make it a little easier to wire up a test, it let's you skip the createMock, and then calling the settter yourself.