I have a service method in FooService
public void doSomething(){
ArrayList<Foo> fooList = ...;
barService.batchAddFoos(fooList);
List<String> codeList = new ArrayList<>();
for (Foo foo : fooList) {
codeList.add(foo.getCode());
}
String key = "foo_codes";
redisService.sadd(key,codeList.toArray(new String[]{}));
// other code also need use code
}
BarService.batchAddFoos
for (Foo foo : foos) {
foo.setCode(UUID.randomUUID().toString()); // dynamically generate the code value
}
Then I have a unit test to test FooService logic
#Test
public void doSomething() throws Exception {
fooService.doSomething();
ArgumentCaptor<List<Foo>> fooListCaptor = ArgumentCaptor.forClass(List.class);
verify(barService).batchAddFoos(fooListCaptor.capture());
List<Foo> fooList = fooListCaptor.getValue();
Assert.assertNotNull(fooList.get(0).getCode()); // check code value is generated successfully
List<String> codeList = new ArrayList<>();
for (Foo foo : fooList) {
codeList.add(foo.getCode());
}
verify(redisService).sadd("foo_codes",codeList.toArray(new String[]{}));
}
but it is failed, because the code value is null, actually it does not execute any code in BarService.batchAddFoos.I even tried to explicitly populate code value,
fooList.get(0).setCode("aaa");
fooList.get(1).setCode("bbb");
but it is still failed.
Argument(s) are different! Wanted:
redisService.sadd("foo_codes", "aaa", "bbb");
Actual invocation has different arguments:
redisService.sadd("foo_codes", null, null);
Any idea to solve this problem?
Since the fooList is a local variable of the FooService.doSomething, you cannot populate it from the test. Your test will not fail, if assertion will be as following:
Mockito.verify(barService).batchAddFoos(fooListCaptor.capture());
List<Foo> fooList = fooListCaptor.getValue();
//Assert.assertNotNull(fooList.get(0).getCode());
Assert.assertFalse(fooList.isEmpty());
...
If you will initialize the code in the Foo constructor with Strings.EMPTY or any other not null value, your original assertion will work.
As such scenario, could populate some properties of some object parameters as you like, e.g.
doAnswer(new Answer() {
#Override
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
List<Foo> fooList = invocationOnMock.getArgumentAt(0, List.class);
fooList.get(0).setCode("aaa"); // explicitly specify the first foo object have code of "aaa"
fooList.get(1).setCode("bbb"); // explicitly specify the second foo object have code of "bbb"
return null;
}
}).when(barService).batchAddFoos(anyList());
Related
I have a piece of code below where Employee class creates object of AppraisalCalculator using reflection. I want to mock this AppraisalCalculator object using PowerMockito.
class AppraisalCalculator {
public int appraisal() {
return 300;
}
}
class Employee {
public int updateSalary() {
// line 1
AppraisalCalculator ac =
AppraisalCalculator.class.getConstructor().newInstance();
return ac.appraisal();
}
}
class TestRunner {
#Test
public void test() {
AppraisalCalulator acMock=PowerMockito.mock(AppraisalCalculator.class);
PowerMockito
.whenNew(AppraisalCalculator.class)
.withNoArguments()
.thenReturn(600);
Employee emp = new Employee();
int actualValue = emp.updateSalary();
int expectedValue=600;
Assert.equals(expectedValue,actualValue);
}
}
Here, even though I have mocked the Appraisal calculator object, it still calls the real appraisal() method from AppraisalCalculator. If the actual AppraisalCalculator at line 1 is created using new Operator instead of newInstance() then this mocking works.
Can anyone explain why this is not working if the actual object is created using reflection? What can I do to mock this Object in such scenario?
Let me first start by rephrasing your question will fully working code.
#RunWith(PowerMockRunner.class)
#PrepareForTest(Employee.class)
public class TestRunner {
#Test
public void test() throws Exception {
AppraisalCalculator acMock = PowerMockito.mock(AppraisalCalculator.class);
PowerMockito
.whenNew(AppraisalCalculator.class)
.withNoArguments()
.thenReturn(acMock);
when(acMock.appraisal()).thenReturn(600);
Employee emp = new Employee();
int actualValue = emp.updateSalary();
int expectedValue = 600;
assertEquals(expectedValue, actualValue);
}
}
Then, the way PowerMock works is that the PowerMockRunner will look at each class that needs to be prepared (here Employee), then look for a call to the constructor we want to replace and do it. This is done at class loading. The real class bytecode calling the constructor is replaced by the one returning the mock.
The thing is that if you are using reflection, PowerMock can't know by reading the bytecode that this constructor will be called. It will only be known dynamically afterwards. So no mocking done.
If you really do need to create the class to be mocked by reflection, I would actually refactor the code a bit.
In Employee I would add something like
protected AppraisalCalculator getCalculator() {
try {
return AppraisalCalculator.class.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
while is a method dedicated to isolate the calculator construction.
The, just create a child class
#Test
public void testWithChildClass() {
// Note that you don't need PowerMock anymore
AppraisalCalculator acMock = Mockito.mock(AppraisalCalculator.class);
when(acMock.appraisal()).thenReturn(600);
Employee emp = new Employee() {
#Override
protected AppraisalCalculator getCalculator() {
return acMock;
}
};
int actualValue = emp.updateSalary();
int expectedValue = 600;
assertEquals(expectedValue, actualValue);
}
or a partial mock (spy)
#Test
public void test2() {
// No PowerMock either here
AppraisalCalculator acMock = Mockito.mock(AppraisalCalculator.class);
when(acMock.appraisal()).thenReturn(600);
Employee emp = spy(new Employee());
doReturn(acMock).when(emp).getCalculator();
int actualValue = emp.updateSalary();
int expectedValue = 600;
assertEquals(expectedValue, actualValue);
}
ok - tried looking /reading and not sure i have an answer to this.
I have a Utility class which wraps a static ConcurrentLinkedQueue internally.
The utility class itself adds some static methods - i dont expect to call new to create an instance of the Utility.
I want to intercept the getProperty calls the utility class - and implement these internally in the class definition
I can achieve this by adding the following to the utility classes metaclass, before i use it
UnitOfMeasure.metaClass.static.propertyMissing = {name -> println "accessed prop called $name"}
println UnitOfMeasure.'Each'
however what i want to do is declare the interception in the class definition itself. i tried this in the class definition - but it never seems to get called
static def propertyMissing (receiver, String propName) {
println "prop $propName, saught"
}
i also tried
static def getProperty (String prop) { println "accessed $prop"}
but this isnt called either.
So other than adding to metaClass in my code/script before i use, how can declare the in the utility class that want to capture property accesses
the actual class i have looks like this at present
class UnitOfMeasure {
static ConcurrentLinkedQueue UoMList = new ConcurrentLinkedQueue(["Each", "Per Month", "Days", "Months", "Years", "Hours", "Minutes", "Seconds" ])
String uom
UnitOfMeasure () {
if (!UoMList.contains(this) )
UoMList << this
}
static list () {
UoMList.toArray()
}
static getAt (index) {
def value = null
if (index in 0..(UoMList.size() -1))
value = UoMList[index]
else if (index instanceof String) {
Closure matchClosure = {it.toUpperCase().contains(index.toUpperCase())}
def position = UoMList.findIndexOf (matchClosure)
if (position != -1)
value = UoMList[position]
}
value
}
static def propertyMissing (receiver, String propName) {
println "prop $propName, saught"
}
//expects either a String or your own closure, with String will do case insensitive find
static find (match) {
Closure matchClosure
if (match instanceof Closure)
matchClosure = match
if (match instanceof String) {
matchClosure = {it.toUpperCase().contains(match.toUpperCase())}
}
def inlist = UoMList.find (matchClosure)
}
static findWithIndex (match) {
Closure matchClosure
if (match instanceof Closure)
matchClosure = match
else if (match instanceof String) {
matchClosure = {it.toUpperCase().contains(match.toUpperCase())}
}
def position = UoMList.findIndexOf (matchClosure)
position != -1 ? [UoMList[position], position] : ["Not In List", -1]
}
}
i'd appreciate the secret of doing this for a static utility class rather than instance level property interception, and doing it in class declaration - not by adding to metaClass before i make the calls.
just so you can see the actual class, and script that calls - i've attached these below
my script thats calling the class looks like this
println UnitOfMeasure.list()
def (uom, position) = UnitOfMeasure.findWithIndex ("Day")
println "$uom at postition $position"
// works UnitOfMeasure.metaClass.static.propertyMissing = {name -> println "accessed prop called $name"}
println UnitOfMeasure[4]
println UnitOfMeasure.'Per'
which errors like this
[Each, Per Month, Days, Months, Years, Hours, Minutes, Seconds]
Days at postition 2
Years
Caught: groovy.lang.MissingPropertyException: No such property: Per for class: com.softwood.portfolio.UnitOfMeasure
Possible solutions: uom
groovy.lang.MissingPropertyException: No such property: Per for class: com.softwood.portfolio.UnitOfMeasure
Possible solutions: uom
at com.softwood.scripts.UoMTest.run(UoMTest.groovy:12)
Static version of propertyMissing method is called $static_propertyMissing:
static def $static_propertyMissing(String name) {
// do something
}
This method gets invoked by MetaClassImpl at line 1002:
protected static final String STATIC_METHOD_MISSING = "$static_methodMissing";
protected static final String STATIC_PROPERTY_MISSING = "$static_propertyMissing";
// ...
protected Object invokeStaticMissingProperty(Object instance, String propertyName, Object optionalValue, boolean isGetter) {
MetaClass mc = instance instanceof Class ? registry.getMetaClass((Class) instance) : this;
if (isGetter) {
MetaMethod propertyMissing = mc.getMetaMethod(STATIC_PROPERTY_MISSING, GETTER_MISSING_ARGS);
if (propertyMissing != null) {
return propertyMissing.invoke(instance, new Object[]{propertyName});
}
} else {
// .....
}
// ....
}
Example:
class Hello {
static def $static_propertyMissing(String name) {
println "Hello, $name!"
}
}
Hello.World
Output:
Hello, World!
If you would like to extract, run or assert argument returned by or called to a method.
This will extract arguments from first and 2nd argument and return Ticket object.
when(mockTicketMaker.getTicket(any(Double.class),any(String.class)))
.thenAnswer(new Answer<String>(){
private int ticketNum=1;
#Override public Ticket answer(InvocationOnMock invocation) throws Throwable {
Double price=(Double)invocation.getArguments()[0];
String destination = (String) invocation.getArguments()[1];
assertEquals(new Double(123.56), price);
return new Ticket();
}
}
);
It looks like you want to assert on the arguments passed to a method. Rather than use an inline answer and assert within the answer, a more elegant solution is provided by Mockito in the form of the ArgumentCaptor<> class.
Given
public class TicketMaker {
public void getTicket(Double arg1, String arg2) {
}
}
You can write the following in a test
#Test
public void captureArguments() {
TicketMaker mockTicketMaker = Mockito.mock(TicketMaker.class);
mockTicketMaker.getTicket(23.0d, "something");
ArgumentCaptor<Double> doubleCaptor = ArgumentCaptor.forClass(Double.class);
ArgumentCaptor<String> stringCaptor = ArgumentCaptor.forClass(String.class);
Mockito.verify(mockTicketMaker).getTicket(doubleCaptor.capture(), stringCaptor.capture());
assertThat(doubleCaptor.getValue()).isEqualTo(23.0d);
assertThat(stringCaptor.getValue()).isEqualTo("something");
}
In the section on handling Java Beans with Groovy of Groovy In Action, I found this script (slightly modified):
class Book{
String title
}
def groovyBook = new Book()
// explicit way
groovyBook.setTitle('What the heck, really ?')
println groovyBook.getTitle()
// short-hand way
groovyBook.title = 'I am so confused'
println groovyBook.title
There are no such methods in the class Book so how does that work ?
Yes, they are auto defined and calling book.title is actually calling book.getTitle()
See http://groovy.codehaus.org/Groovy+Beans
You can see this in action with the following script:
def debug( clazz ) {
println '----'
clazz.metaClass.methods.findAll { it.name.endsWith( 'Name' ) || it.name.endsWith( 'Age' ) }.each { println it }
}
class A {
String name
int age
}
debug( A )
// Prints
// public int A.getAge()
// public java.lang.String A.getName()
// public void A.setAge(int)
// public void A.setName(java.lang.String)
// Make name final
class B {
final String name
int age
}
debug( B )
// Prints
// public int B.getAge()
// public java.lang.String B.getName()
// public void B.setAge(int)
// Make name private
class C {
private String name
int age
}
debug( C )
// Prints
// public int C.getAge()
// public void C.setAge(int)
// Try protected
class D {
protected String name
int age
}
debug( D )
// Prints
// public int D.getAge()
// public void D.setAge(int)
// And public?
class E {
public String name
int age
}
debug( E )
// Prints
// public int E.getAge()
// public void E.setAge(int)
Several notes:
For all property fields(public ones only), there are autogenerated accesors.
Default visibility is public. So, you should use private/protected keyword to restrict accessor generation.
Inside an accessor there is direct field access. like this.#title
Inside a constructor you have direct access to! This may be unexpected.
For boolean values there are two getters with is and get prefixes.
Each method with such prefixes, even java ones are treated as accessor, and can be referenced in groovy using short syntax.
But sometimes, if you have ambiguous call there may be class cast exception.
Example code for 4-th point.
class A{
private int i = 0;
A(){
i = 4
println("Constructor has direct access. i = $i")
}
void setI(int val) { i = val; println("i is set to $i"); }
int getI(){i}
}
def a = new A() // Constructor has direct access. i = 4
a.i = 5 // i is set to 5
println a.i // 5
4-th note is important, if you have some logic in accessor, and want it to be applied every time you call it. So in constructor you should explicit call setI() method!
Example for 7
class A{
private int i = 0;
void setI(String val) { println("String version.")}
void setI(int val) { i = val; println("i is set to $i"); }
}
def a = new A()
a.i = 5 // i is set to 5
a.i = "1s5" // GroovyCastException: Cannot cast object '1s5' with class 'java.lang.String' to class 'int'
So, as I see property-like access uses first declared accessor, and don't support overloading. Maybe will be fixed later.
Groovy generates public accessor / mutator methods for fields when and only when there is no access modifier present. For fields declared as public, private or protected no getters and setters will be created.
For fields declared as final only accessors will be created.
All that applies for static fields analogously.
I have some code that put simply, sets an object to a state of PROCESSING, does some stuff, then sets it to SUCCESS. I want to verify that the PROCESSING save is done with the correct values.
The problem is when the verify() tests are performed, .equals() is called on the object as it is at the end of the test, rather than halfway through.
For example the code:
public void process(Thing thing) {
thing.setValue(17);
thing.setStatus(Status.PROCESSING);
dao.save(thing);
doSomeMajorProcessing(thing);
thing.setStatus(Status.SUCCESS);
dao.save(thing);
}
I want to test:
public void test() {
Thing actual = new Thing();
processor.process(actual);
Thing expected = new Thing();
expected.setValue(17);
expected.setStatus(Status.PROCESSING);
verify(dao).save(expected);
// ....
expected.setStatus(Status.SUCCESS);
verify(dao).save(expected);
}
On the first verify, actual.getStatus() is Status.SUCCESS, as Mockito just keeps a reference to the object and can only test it's value at the end.
I have considered that if a when(...) where involved then .equals() would be called at the correct time and the result would only happen if Thing was what I wanted it to be. However, in this case .save() returns nothing.
How can I verify that the object is put into the correct states?
Ok, I found a solution, but it's pretty horrible. Verify is no good to me because it runs too late, and stubbing is hard because the method returns a void.
But what I can do is stub and throw an exception if anything but the expected is called, while validating that something is called:
public void test() {
Thing actual = new Thing();
Thing expected = new Thing();
expected.setValue(17);
expected.setStatus(Status.PROCESSING);
doThrow(new RuntimeException("save called with wrong object"))
.when(dao).saveOne(not(expected));
processor.process(actual);
verify(dao).saveOne(any(Thing.class));
// ....
expected.setStatus(Status.SUCCESS);
verify(dao).saveTwo(expected);
}
private <T> T not(final T p) {
return argThat(new ArgumentMatcher<T>() {
#Override
public boolean matches(Object arg) {
return !arg.equals(p);
}
});
}
This infers that expected is called. Only drawback is that it'll be difficult to verify the method twice, but luckily in my case both DAO calls are to different methods, so I can verify them separately.
Why not just mock the Thing itself and verify that? eg:
public class ProcessorTest {
#Mock
private Dao mockDao;
#InjectMocks
private Processor processor;
#BeforeMethod
public void beforeMethod() {
initMocks(this);
}
public void test() {
Thing mockThing = Mockito.mock(Thing.class);
processor.process(thing);
verify(mockThing).setStatus(Status.PROCESSING);
verify(mockThing).setValue(17);
verify(mockDao).save(mockThing);
verify(mockThing).setStatus(Status.SUCCESS);
}
If you want to explicitly test the order in which these things happen, use an InOrder object:
public void inOrderTest() {
Thing mockThing = Mockito.mock(Thing.class);
InOrder inOrder = Mockito.inOrder(mockThing, mockDao);
processor.process(mockThing);
inorder.verify(mockThing).setStatus(Status.PROCESSING);
inorder.verify(mockThing).setValue(17);
inorder.verify(mockDao).save(mockThing);
inorder.verify(mockThing).setStatus(Status.SUCCESS);
inorder.verify(mockDao).save(mockThing);
}
Mockito has a problem verifying mutable objects. There is an open issue about this (http://code.google.com/p/mockito/issues/detail?id=126)
Maybe you should switch to EasyMock. They use a record/playback pattern and do the verification at the time of the call in contrary to Mockito, where the verification happens after the call.
This Mockito version of the test has the mentioned problem:
#Test
public void testMockito() {
Processor processor = new Processor();
Dao dao = Mockito.mock(Dao.class);
processor.setDao(dao);
Thing actual = new Thing();
actual.setValue(17);
processor.process(actual);
Thing expected1 = new Thing();
expected1.setValue(17);
expected1.setStatus(Status.PROCESSING);
verify(dao).save(expected1);
Thing expected2 = new Thing();
expected2.setValue(19);
expected2.setStatus(Status.SUCCESS);
verify(dao).save(expected2);
}
This EasyMock version works fine:
#Test
public void testEasymock() {
Processor processor = new Processor();
Dao dao = EasyMock.createStrictMock(Dao.class);
processor.setDao(dao);
Thing expected1 = new Thing();
expected1.setValue(17);
expected1.setStatus(Status.PROCESSING);
dao.save(expected1);
Thing expected2 = new Thing();
expected2.setValue(19);
expected2.setStatus(Status.SUCCESS);
dao.save(expected2);
EasyMock.replay(dao);
Thing actual = new Thing();
actual.setValue(17);
processor.process(actual);
EasyMock.verify(dao);
}
In my example doSomeMajorProcessing sets value to 19.
private void doSomeMajorProcessing(Thing thing) {
thing.setValue(19);
}
After reviewing https://code.google.com/archive/p/mockito/issues/126
I was able to get my version of this working (Java 15, Mockito 3.6.28):
// ========= CODE ==========
public void process(Thing thing) {
thing.setValue(17);
thing.setStatus(Status.PROCESSING);
dao.save(thing);
doSomeMajorProcessing(thing);
thing.setStatus(Status.SUCCESS);
dao.save(thing);
}
// ========= TEST ==========
// ++++++ NOTE - put this at class level
private final Dao dao = mock(Dao.class, withSettings().defaultAnswer(new ClonesArguments()));
public void test() {
Thing actual = new Thing();
processor.process(actual);
ArgumentCaptor<Thing> captor = ArgumentCaptor.for(Thing.class);
verify(dao, times(2)).save(captor.capture());
List<Things> savedCalls = captor.getAllValues();
assertEquals(Status.PROCESSING, savedCalls.get(0).getStatus());
assertEquals(Status.SUCCESS, savedCalls.get(1).getStatus());
}
Using argThat with a hamcrest Matcher should do the trick. The Matcher would match its passed thing if the thing has the PROCESSING status:
public class ProcessingMatcher extends BaseMatcher<Thing> {
#Override
public boolean matches(Object item) {
if (item instanceof Thing) {
return ((Thing) item).getStatus() == Status.PROCESSING;
}
return false;
}
#Override
public void describeTo(Description description) {
description.appendText(" has the PROCESSING status");
}
}
And then in your test, use the following code :
public class MyTest {
public void test() {
//...
mockDao.save(argThat(hasTheProcessingStatus()));
}
static ProcessingMatcher hasTheProcessingStatus() {
return new ProcessingMatcher();
}
}