Can gmock mock static methods of Java classes? Alternative? - java

I could not get it to work. It's like the method is not mocked.
Are there alternative groovy testing frameworks that work better to mock static Java methods?
Update 02/Mar/2011: Adding code:
I am actually trying to mock the Scala XML.loadXml (I am trying Groovy for unit testing) class:
This is my test case:
// ContentManagementGatewayTest.groovy
class ContentManagementGatewayTest extends GMockTestCase
{
void testGetFileList()
{
// Preparing mocks code will go here, see below
play {
GetFileGateway gateway = new GetFileGateway();
gateway.getData();
}
}
}
// GetFileGateway.scala
class GetFileGateway {
def getData()
{
// ...
val xmlData = XML.loadData("file1.txt");
}
}
I tried testing using both gmock and metaClass:
// metaClass:
XML.metaClass.'static'.loadFile = {file ->
return "test"
}
// gmock:
def xmlMock = mock(XML)
xmlMock.static.loadFile().returns(stream.getText())

You can do this using Groovy (metaprogramming), you don't need any additional libraries. Here's a (stupid) example, that overrides Collections.max such that it always returns 42. Run this code in the Groovy console to test it.
// Replace the max method with one that always returns 42
Collections.metaClass.static.max = {Collection coll ->
return 42
}
// Test it out, if the replacement has been successful, the assertion will pass
def list = [1, 2, 3]
assert 42 == Collections.max(list)
Update
You mentioned in a comment that my suggestion didn't work. Here's another example that corresponds to the code you've shown in your question. I've tested it in the Groovy console and it works for me. If it doesn't work for you, tell me how your testing differs from mine.
Math.metaClass.static.random = {-> 0.5}
assert 0.5 == Math.random()

Scala doesn't have static methods, so it is no wonder you couldn't mock one -- it doesn't exist.
The method loadXml to which you refer is found on the XML object. You can get that object from Java with scala.XML$.MODULE$, but, since objects are singleton, its class is final.
Alas, loadXML is defined on the class XMLLoader, which the object XML extends, not on the object XML itself. So you can simply do a normal mock of XMLLoader. It will lack a few methods, but perhaps it will do all you need.

The documentation for GMock seems to show that you can just do:
Mocking static method calls and
property call is similar to standard
method calls, just add the static
keyword:
def mockMath = mock(Math)
mockMath.static.random().returns(0.5)
play {
assertEquals 0.5, Math.random()
}

Related

Mocking Map parameter in Spock Framework Java test

I am having difficulty in getting a test to work using Spock Framework in a Java project. I have the following:
- Person.class
- Attribute.class
I have a service class which is being mocked in my test. The method I am trying to mock has the following signature:
serviceClass.call(Map<Person, List<Attribute>> map)
When I mock it purely using wildcards like:
serviceClass.call(_) >> MockReturnObject
Everything works as expected. The call in the service class will return the MockReturnObject.
However, for my specific case I need to specify the Person object I am passing in and assign it a specific MockReturnObject. Like:
serviceClass.call([(PersonA):_)]) >> MockReturnObjectA
or
def listWildcard = _
serviceClass.call(Map.of(PersonA, listWildcard)) >> MockReturnObjectA
Neither of these approaches work and the call ends up returning null instead of MockReturnObjectA (I assume it is because it is failing to match the arguments). I am unfortunately not too experienced with Spock and my attempt to search through documentation on handling Maps in this scenario has not come up fruitful. I would appreciate anyone able to offer any guidance.
I don't think it makes a difference but PersonA is passed in to an entry method in the serviceClass in a list like;
List<Attribute> list = getAttributeList()
entryClass.process(List<Person> personList) {
personList.forEach(person -> serviceClass.call(Map.of(person, list))
}
So in my tests, the "when" is:
entryClass.process([PersonA, PersonB, PersonC])
With all 3 being Mock(Person.class) with their own behaviours.
When you use an object as parameter Spock will use Groovy equality to compare the argument. However, if it is too complicated to construct the reference object, you can use code argument constraints instead to programmatically check the actual argument.
serviceClass.call({ it[PersonA] == attributeList }) >> MockReturnObject
As you've shared very little code this is the best example I can give.

Junit test cases for StreamSupport

I am new to test cases I tried several ways to write test case for below piece of code but I never succeeded. How to write junit test case for below code using Powermockito?
StreamSupport.stream(irSet.spliterator(), false)
.filter(iResultRow -> iResultRow !=null)
.mapToInt(iResultRow ->{
String event = iResultRow.get("STF_TY_GH");
return StringUtils.isNotBlank(event) ? Integer.parseInt(event) : 1;
}).findFirst().orElse(1);
While, using a descent amount of mocks you can mock every single call, let me suggest you an alternative approach.
So you have a stream produced out of some input set (irSet) variable. This stream makes "some" processing and returns an integer result.
So if you "imagine" Its a black box: a kind of function that looks like this:
int doSomething(Set<SomeRow> irSet) {
... your implementation is here...
}
In this case, you might want to test what it does by supplying the various input sets and expecting for some outputs. What if there are null-s in the input? Will it fail or filter out what's needed. What if the set is empty? What if there is SomeRow that really has STF_TY_GH data, what if the set doesn't have such a row?
Here is a test for example:
#Test
public void test_rows_with_null_are_processed_correctly() {
// setup:
Set<SomeRow> input = ...// prepare a set with null values
// when:
Integer actual = underTest.doSomething(input)
// then:
// verify this "actual" whether it should be 1 or something else
}
All-in-all, use mocks only for interactions (with something you can't really instantiate like DB API/remote HTTP calls) or for something that is not related to the tested code and is used as a dependency the tested code interacts with. After all, the goal of unit tests is to test your code (the implementation of doSomething in this case and not to mock everything out).

Writing Unittest which takes 2 list

I am a new Junit Learner I would like to test my code according to 2 list class. However I never saw any example of that.
My real code is below :
public static List<JourneyType> applyFilter(List<JourneyType> journeyList, List<AvailabilityFilterOptionType> filterOptions)
{
List<JourneyType> filteredJourneyList = new ArrayList<>();
filteredJourneyList = applyStopFilters(journeyList, filterOptions);
filteredJourneyList = applyCarrierFilters(filteredJourneyList, filterOptions);
filteredJourneyList = applyRbdFilters(filteredJourneyList, filterOptions);
filteredJourneyList = applyDurationFilter(filteredJourneyList, filterOptions);
return filteredJourneyList;
}
and my test scenario :
#Test
public void testApplyFilter()
{
fail("Not yet implemented");
}
Thank you in advanced
Actually, this is pretty simple.
#Test
public void testApplyFilter()
{
assertThat(someObject.applyFilter(journies, filters), is(expectedOutcome));
}
In other words: you know what this method is supposed to do. ( Well, such knowledge is the prerequisite for testing stuff. When you don't know what your code is doing, there is no point in verifying its correctness via testing...)
As in: given some known input data, you should be able put down an expectation about output coming back. And that is what you check for.
Of course, the tricky part could be to correctly identify dependencies, and mock them where needed.
But ideally, your test should just be that: testing the public contract of your method under test. Something goes in, and you check that the output coming back meets your expectations. Ideally, you have to mock nothing for such tests, because you do not at all rely on testing implementation details. You only test the public contract "given this input, this is the expected output".
( where: assertThat() is just a different type of assert, and is() is a hamcrest matcher. There are many other hamcrest matchers, such as containsInAnyOrder() (that one is really neat if you don't care about the order of elements returned, but one has to understand that is used slightly different, it would need containsInAnyOrder(expectedOutcomeList.toArray()) methinks )

PowerMockito verifyNew withArguments of an object and an array of objects

i am trying to test that a method creates an object. i have it almost working using PowerMockito.verifyNew().withArguments() however, the Arguments that are passed to the constructor are an object and an ArrayList of objects. the output of the test is:
Actual
invocationSubstitute.performSubstitutionLogic(
1,
6,
11,
13,
[au.edu.sccs.csp3105.NBookingPlanner.Person#2449cff7],
au.edu.sccs.csp3105.NBookingPlanner.Room#62da83ed,
"description"
);
Expected
invocationSubstitute.performSubstitutionLogic(
1,
6,
11,
13,
[au.edu.sccs.csp3105.NBookingPlanner.Person#40bffbca],
au.edu.sccs.csp3105.NBookingPlanner.Room#42a9a63e,
"description"
);
i can see that the problem is the objects are the same type but not the same object, is there a way of saying the Expected object is of the correct type?
test:
#RunWith(PowerMockRunner.class)
#PrepareForTest({Planner.class, Meeting.class})
public class MonthInput {
Planner planner;
#Rule
public final TextFromStandardInputStream systemInMock = emptyStandardInputStream();
#Rule
public final ExpectedSystemExit exit = ExpectedSystemExit.none();
#SuppressWarnings("deprecation")
#Before
public void setup() throws Exception {
Meeting meetingMock = Mockito.mock(Meeting.class);
PowerMockito.whenNew(Meeting.class).withAnyArguments().thenReturn(meetingMock);
}
#Test
public void MonthInputofless5() throws Exception {
// make spy
planner = Mockito.spy(Planner.class);
//override main menu with do nothing
Mockito.doNothing().when(planner).mainMenu();
//provide inputs
systemInMock.provideLines("1","6","11","13","ML13.218","Mark Colin","done","description");
//set expected outputs
ArrayList<Person> attendees = new ArrayList<Person>();
attendees.add(new Person("Mark Colin"));
Room where = new Room("ML13.218");
//call the method
planner.scheduleMeeting();
//set passing terms
PowerMockito.verifyNew(Meeting.class).withArguments(1,6,11,13,attendees,where,"description");
}
Fix your code
A verify simple fix on your classes: implement hashCode and equals on Person and Room so Powermock verification can actually compare two objects for equality and not just rely on the object reference.
Fix your tests
If you don't want to fix your code, but the test, you could either use a Mockito matcher (i.e. org.mockito.Matchers.eq or org.mockito.Matchers.any). But please note, that eq relies on equals and won't work unless you implement it (see above). But any would match any object of that type (surprise!)
PowerMockito.verifyNew(Meeting.class)
.withArguments(eq(1),eq(6),eq(11),eq(13),
any(List.class),
any(Room.class),
eq("description"));
If the actual value matters, you could use an ArgumentCapture instead of a matcher and check the captured value.
Theoretically, it should look like this:
final ArgumentCaptor<Person> personCaptor = forClass(Person.class);
final ArgumentCaptor<Room> roomCaptor = forClass(Room.class);
PowerMockito.verifyNew(Planner.class)
.withArguments(eq(1),eq(6),eq(11),eq(13),
personCaptor.capture(),
roomCaptor.capture(),
eq("description"));
final Person passedParam = personCaptor.getValue();
//do your comparison here
But I didn't get the capture example running, so maybe that's only possible with plain Mockito.
Just don't!
All that said, you should verify your overall approach. Using Whitebox-Testing may create very brittle tests and won't help much in refactoring and may further foster bad class design.
The imprudent use of Powermockito is an anti-pattern. It's a very mighty tool for testing the untestable, i.e. badly designed legacy code from the dark ages of the internet where the homepages were handcrafted HTMLs and full of wobbly GIFs.
Don't use it for new, greenfield projects. Just don't.
Instead try focusing on the observable result of any action. Invoking the scheduleMeeting() method may produce any result that is more easy to check - it's the result that matters, not the way to get they. Trust me, not a single user gets happier when a constructor was called.
Results could be
an instance of a meeting (as return value, that would be best in your example)
a state change in the planner (any getters?)
a state change in a downstream service / db
a written file
an output written to System.out

mockito - how to check an instance inside a method

I am new to Mockito, I am trying to verify the attributes of an object which gets created inside a method.
pseudo code below:
class A{
...
public String methodToTest(){
Parameter params = new Parameter(); //param is basically like a hashmap
params.add("action", "submit");
return process(params);
}
...
public String process(Parameter params){
//do some work based on params
return "done";
}
}
I want to test 2 things:
when I called methodToTest, process() method is called
process() method is called with the correct params containing action "submit"
I was able to verify that process() is eventually called easily using Mockito.verify().
However trying to check that params contains action "submit" is very difficult so far.
I have tried the following but it doesn't work :(
BaseMatcher<Parameter> paramIsCorrect = new BaseMatcher<Parameter>(){
#Overrides
public boolean matches(Object param){
return ("submit".equals((Parameter)param.get("action")));
}
//#Overrides description but do nothing
}
A mockA = mock(A);
A realA = new A();
realA.methodToTest();
verify(mockA).process(argThat(paramIsCorrect))
Any suggestion ?
If you have got verify() to work, presumably it is just a case of using an argument matcher to check the contains of params.
http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#3
The example given in the above docs is verify(mockedList).get(anyInt()). You can also say verify(mockedList).get(argThat(myCustomMatcher)).
As an aside, it sounds like you are mocking the class under test. I've found that this usually means I haven't thought clearly about either my class or my test or both. In your example, you should be able to test that methodToTest() returns the right result irrespective of whether or not it calls process() because it returns a String. The mockito folk have lots of good documentation about this sort thing, particularly the "monkey island" blog: http://monkeyisland.pl/.
Just pass Parameter in as a constructor argument to a constructor of the class A, then use a mocked instance/implementation of Parameter in your test and verify on the mock. That is how it is normally done - you separate your classes and compose them using constructor injection, that enables you to pass in mocks for testing purposes (it also allows rewiring the application and exchanging some commons a lot easier).
If you need to create Parameter on every function invocation you should use a factory that creates Parameter instances and pass that in. Then you can verify on the factory as well as the object created by the factory.

Categories