Mockito: verify arguments passed to new - java

I'm trying to work out how to verify the parameters passed to a mocked constructor in Mockito. A simplified version of my code is:
class Mocked {
Mocked(String first, String second, int value) {
}
}
class Target {
void testMe() {
new Mocked("Hello", "World", 99);
}
}
#Test
public void test_Target() {
try (
MockedConstruction<Mocked> mockedNew = mockConstruction(Mocked.class);
) {
new Target().testMe();
Mocked mocked = mockedNew.constructed().get(0);
// TODO: verify all arguments passed to mocked
}
}
The class I'm trying to test is "Target"
Target uses an instance of the "Mocked" class. In real code code I'll want to use an actual instance of Mocked, but for the purposes of testing I want to mock it out so I can test "Target" in isolation of "Mocked". I've used the mockConstruction construct to do this.
In my final version of my code the arguments passed to the Mocked constructor are not hardcoded. Instead there will be some business logic to derive them, so and I want to verify they have been derived out correctly. But how?
None of the examples I've Googled show show me how to do this, and org.mockito.Mockito.verify() doesn't appear to have a way to test a constructor.
The only solution I can see is to add mock initialiser function that copies the argument into local variables. But this involves making those variables effectively final (so final one element array) and ugly casts. Surely there has to be something better than that!
What have I missed?

As far as I know, this is not possible using the Mockito API.
You can try a design change where a new MockedFactory class is responsible for creating Mocked objects. You can create a MockMockedFactory for your tests and inject it into Target to use. You will be able to verify the methods called on this factory by the class under test. Not the nicest, adds boilerplate code, but works.
Also, I guess the newly created object is not returned as testing would not be a problem then. It is worth considering if the method you are testing isn't too big doing too many things at once. Maybe some other refactors could help make it more testable.
Or maybe this one: https://groups.google.com/g/mockito/c/WqPlcNrvbOw?pli=1

Related

Test lambda expressions called by dependencies

I am trying to test some code inside lambda expression which is a call back from another class.
class EmailSender {
private EmailBuilder emailBuilder;
public void send() {
String testEmail = emailBuilder.buildEmail("Test Email", bodyContentAppender());
//send testEmail
}
private Consumer<Email> bodyContentAppender() {
//how to test this through JUnit?
return email -> email.appendBody("Body Content");
}
}
interface EmailBuilder {
String buildEmail(String templateName, Consumer<Email> contentAppender);
}
The lambda expression in the method getBodyContent is called from EmailBuilder which is a mocked dependency in the JUnit test for EmailSender. Since I am mocking the behavior of EmailBuilder, the code inside getBodyContentis not called from tests. How to test such piece?
EDIT:
Capturing the lambda expression through Argument Captors is not a solution in this case as the behavior of EmailBuilder is mocked and the actual methods are not called. Secondly, email.appendBody does some transformations on an object which is passed by an external API and not straightforward to create.
What you are trying to do here is essentially to verify that a factory method did in fact really return the correct object. There is this related question, where the consensus is to not test the result of a factory method beyond verifying that it does indeed return an object of the correct type. The behavior of that object should be tested in the UnitTests for that type.
In an answer to this related question on unit testing lambdas Stuart Marks argues that
If the code in the lambda is complex enough that it warrants testing, maybe that code ought to be refactored out of the lambda, so that it can be tested using the usual techniques.
Now, the real question is: If this was not a lambda, but a concrete class MyBodyContentAppender that implements the functional interface Consumer<Email>, how would you unit test that? What kinds of test would you write for this class?
You would probably write tests to verify that, given an Email, invoking accept() does indeed invoke appendBody() with the appropriate parameters, perhaps that invoking it with a null argument throws a NullPointerException etc. You would possibly not verify that email.appendBody() works as expected, because that is covered by the tests for Email. You may have to mock Email for these tests if it is difficult to create.
Well, all of these tests can also be performed for the lambda. Your problem is that the factory and the type of the created object are both private, so from the perspective of your test, the only way to access that object is via the parameter passed to the (mocked) emailBuilder.buildEmail().
If you use Mockito for mocking the emailBuilder, you could capture the arguments to this method via ArgumentCaptors (see 15. Capturing arguments for further assertions (Since 1.8.0)), I'm sure other mocking libraries provide similar functionality.
Most mocking frameworks allow you to check arguments that are used when invoking methods on mocked object. Respectively, you can capture them.
So:
acquire the parameter passed
simply invoke the "code" that it represents, and check if that makes the expected updates to an Email object you provided.
It will be easier to test if you actually supply the body content as an argument, and make sure the method is public. If you intend to keep the method as private, then you should test the public method calling it.
public Consumer<Email> getBodyContent(String body) {
//how to test this through JUnit?
return email -> email.appendBody(body);
}
Then you can test it as
#Test
public void testGetBodyContent(){
.... //send different arguments and assert
....
}
So when you want to unit test your code you must ensure that it's doing one job at a time. You method is named as getBodyContent but seems like is supposed to do no more work than appending to email body. Hence, you could pull out this method to be public.
Now you could pass the body and get the content.
#Test
public void testGetBodyContent(){
consumer<Email> consumer = EmailSender.getBodyContent();
assertEquals("Email Content", consumer.accept(<mocked Email object>).getBody())
}

Equivalent of Answers.RETURNS_DEEP_STUBS for a spy in mockito

I have been unable to find a way to use "Deep Stubs" for stubbing methods on a spy in Mockito. What I'm looking to do is something like this:
#Spy private Person person = //retrieve person
#Test
public void testStubbed() {
doReturn("Neil").when(person).getName().getFirstName();
assertEquals("Neil", person.getName().getFirstName());
}
The code above compiles with no issues, but upon running the test, it fails saying that the return type (the Name class, in this case) cannot be returned by getName().
Normally, when mocking, you have to use
#Mock(answer = Answers.RETURNS_DEEP_STUBS) for each mocked object. However, spy does not seem to have anything like this.
Has anyone ever successfully done deep stubbed mocking using a spy?
The error I'm receiving is listed below:
String cannot be returned by getName()
getName() should return Name
Due to the nature of the syntax above problem might occur because of:
1. Multithreaded testing
//I'm not doing multithreaded testing
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies with doReturn|Throw() family of methods
//As shown above, I'm already using the doReturn family of methods.
While I'd still like to know if there's a better way to do this, I'd like to post a solution for anyone who comes looking.
The solution below works fine, by requiring you to create a new mock (or even a real object/spy) for each level of your dependencies. In other words, instead of chaining your method calls to create your stub, you mock each level individually.
#Spy private Person person = //retrieve person
#Mock private Name name;
#Test
public void testStubbed() {
doReturn(name).when(person).getName();
doReturn("Neil").when(name).getName();
assertEquals("Neil", person.getName().getFirstName());
}
You can get a little closer to the deep stubs you want by using doAnswer(RETURNS_DEEP_STUBS), but you can't override arbitrarily-deep method calls without taking care to stub their parent calls. I'd stick to manual single-level-deep mocks as you do in your answer, or use even less mocking if possible.
A spy's default behavior is to delegate to its real method call, which will typically return a real object (like your Name) and not a Mockito spy. This means that you won't normally be able to change those objects' behavior using Mockito: a spy isn't really the same class as the object being spied on, but rather is a generated subclass where every field value is copied from the spied-on value. (The copying is an important feature, because a delegating spy would have very unintutitive behavior regarding this, including for method calls and field values.)
Foo foo = new Foo();
foo.intValue = 42;
foo.someObject= new SomeObject();
Foo fooSpy = Mockito.spy(foo);
// Now fooSpy.intValue is 42, fooSpy.someObject refers to the exact same
// SomeObject instance, and all of fooSpy's non-final methods are overridden to
// delegate to Mockito's behavior. Importantly, SomeObject is not a spy, and
// Mockito cannot override its behavior!
So this won't work:
doReturn("Neil").when(person).getName().getFirstName();
// Mockito thinks this call ^^^^^^^^^ should return "Neil".
And neither will this:
doReturn("Neil").when(person.getName()).getFirstName();
// The object here ^^^^^^^^^^^^^^^^ won't be a mock, and even if Mockito
// could automatically make it a mock, it's not clear whether that
// should be the same spy instance every time or a new one every time.
In your situation, I'd choose the following, in order from most preferable to least:
Create a real Name object and install it using doReturn. It looks like Name is a data object (aka value object) after all, which likely means it has no dependencies, solid behavior, and difficult-to-mock state transitions. You may not be gaining anything by mocking it.
Create a mock Name and install it as you do in your answer. This is particularly useful if Name is more complicated than it looks to be, or if it doesn't actually exist in the first place.
Replace getName to return a deep stub...
doAnswer(RETURNS_DEEP_STUBS).when(person).getName();
...which you can then override...
doReturn("Neil").when(person.getName()).getFirstName();
...even for arbitrarily deep values.
doReturn("Gaelic").when(person.getName()
.getEtymology()
.getFirstNameEtymology())
.getOrigin();
As a final editorial, one of the hazards of partial mocks is that it makes it really hard to tell which behavior is real and which is faked; this might make it hard for you to guarantee that the behavior you're testing is prod behavior and not mock behavior. Another hazard of deep stubbing is that you may be violating the Law of Demeter by definition. If you find yourself using this kind of technique often in tests, it may be time to consider rearchitecting your system under test.
#Test
public void listTypeTest() throws Exception {
doCallRealMethod().when(listType).setRecordCount(new BigInteger("556756756756"));
listType.setRecordCount(new BigInteger("556756756756"));
doCallRealMethod().when(listType).getRecordCount();
assertEquals(new BigInteger("556756756756"), listType.getRecordCount());
}

Junit: local variables and void methods

I'm fairly new to unit testing and have been reading a lot of material online, but I'm having a little trouble figuring stuff out.
For example: If I have the following piece of code :
public class RandomClass
{
int a = 4;
public void foo(Object obj)
{
if(a == 4)
{
AnotherObject anotherObj = new AnotherObject();
anotherObj.setAttribute(obj.getFiled());
//Method call that will be suppressed
Anotherclass.anotherMethod(anotherObj);
}
}
}
I thought of writing my junit test case like this:
#Test
public void testFoo()
{
int a=4;
RandomClass randomClass = new RandomClass();
Object object = new Object();
object.setField("hey");
randomClass.foo(object);
}
I have a couple of questions here.
How exactly do I set the integer a from my junit? The way I'm setting it right now doesn't the unit test case any impact. When I debug the unit test, the value of a is NULL so it never passes the if condition!
Also, the method foo returns a void so what can I possibly test/assert?
There are two major techniques when writing unit tests:
Checking the external contract of your class under test. Meaning: you try to write testcases for RandomClass that know nothing about AnotherClass. Instead, your test code only observes behavior of RandomClass objects. In other words: you really don't care about the internal implementation details of RandomClass - because all the things you "want to see" can be observed by checking what RandomClass objects return when you call methods with specific parameters. Occasionally you get there by adding (package protected) getter methods that allow you to inspect some internal state of your class under test.
But sometimes that might not be "good enough"; for example when you know that your class under test must be using some other objects to get its job done. In such situations, you should be looking into mocking objects. In your case, you might want to create a mocked instance of AnotherClass; and then you would use dependency injection in order to provide that object to your class under test.
You see, you actually wrote "hard to test" code - because you are calling new for AnotherClass in your production code. That doesn't seem like a big deal, but depending on what AnotherClass is about ... you really shouldn't do that!
In any case; I recommend you to look into these videos to learn how to write code that works better for unit testing.
A test normally starts with a "setup", "prepare", or "arrange" step, where it creates or modifies the object under test so that it is in the state needed by that particular test.
So, if field a in the RandomClass object needs to have a value 4 (for example), then the test needs to either create the object passing this value as a constructor argument, or to set the value in the object by calling a setter method or by directly accessing the field. In the worst case, you might need to use Reflection to set the field, but that would indicate a design issue in the class being tested.
The next step is to exercise the code under test. This is the "act" step, in the "Arrange, Act, Assert" terminology (AAA, for short).
Finally, the final step is to "assert" (verify) the code being tested did what is was supposed to do.
If the method being tested has void return type, then the test should verify it did what was expected either through state verification or through behavior verification.
In the first case, the test would call some getter method in the object under test, and use it in an "assert" of some kind (for example, an assertEquals(expectedValue, actualValue)).
In the second case, the test would use some mocking library in order to verify that expected calls were made from the code under test to one or more dependencies (other objects or classes on which the class under test depends). For example, here the test could verify that RandomClass#foo did actually call Anotherclass.anotherMethod(...).

Testing a method which calls private void method inside using mockito

I want to test a method which internally calls a void method.
Below is the code
public String process(MKSConnectionParams mksConnectionParam, IProgressMonitor progressMonitor) throws Exception {
if (null != progressMonitor) {
progressMonitor.beginTask("Starting the creation of report", 100);
}
if (null == mksConnectionParam) {
initialize(MksLibFactory.getDefault());
}
else {
initialize(mksConnectionParam, MksLibFactory.getDefault());
}
--------------
}
public void initialize(MKSConnectionParams mksConnectionParam, IMksLibrary mksLibDefault) throws Exception {
paramMKSConnectionParams = mksConnectionParam;
GlobalConstants.hostName = paramMKSConnectionParams.hostname;
GlobalConstants.port = String.valueOf(paramMKSConnectionParams.port);
try {
localISi = mksLibDefault.getSi(paramMKSConnectionParams);
localIIm = mksLibDefault.getIm(paramMKSConnectionParams);
}
catch (MksLibException | AuthenticationError e) {
throw e;
}
ProjectInfo prjInfo = localISi.getProjectInfo(pathToPj);
projRevCmd = prjInfo.getConfigPath().getConfigPath() + "#b=" + projectRevision;
}
I am writing mockito test case for process() method. Testing is getting failed when initialize(mksConnectionParam, MksLibFactory.getDefault()) is called. It is because in the process we are calling real mks connection and I am passing dummy user name and password.
We aren't able to mock this initialize method. Is there any way to do this?
Small pseudocode would be of great help.
Earlier I had initialize method as private. Would changing it to public make any difference?
There are several ways to test this scenario, and different people would advocate different approaches, mostly based on personal preference.
Notice that testing this, will require changes in the code of the class you're testing (I believe you neglected to mention its name). There is one exception, and that's if you're using PowerMock. I won't go into the details here, but you find out more on how to incorporate it into your mockito code here.
Back to regular testing methods, the problem is that you're using the real IMksLibrary instead of a mock, and that's because you obtain a reference to it inside the process method. Here are a few method that you might want to consider:
Change the signature of the process method to receive the reference to the IMksLibrary instance, so that the test code can supply a mock of it
Instead of creating the reference inside the process method inject a reference to the class, either by using some DI framework (e.g. Spring, Guice, CDI, etc.), or as a constructor parameter
Create a protected method called something like getIMjsLibraryInstance() in the class, that will return MksLibFactory.getDefault(), and use it instead of the explicit code (this is the Extract Method refactoring that can be automatically done by most IDEs for Java nowadays). In the test code, you need to create a subclass (this is why it's my least favorite method) which overrides this method and returns a mock, and test the subclass instead of the real class. Notice that this is the ONLY method that you should subclass
You might feel deterred from using the third method, since in effect, you're not really testing the class that you meant to test (but rather a subclass of it). I tend to agree that this has a bed smell to it. However, keep in mind, that unlike the other two methods, this will not require any changes to the clients of the class (this is a pretty strong argument in favor of it).
There are other methods that you can use, but they are pretty similar in nature to the first two methods, and they also require some changes in the code.
If you feel that any "regular" method of testing is not good enough (due to code changes or whatever other reason), you are welcomed to take a look at PowerMock, which will enable you to intercept the static method call that returns the IMksLibrary instance, and return a mock instead. A word of caution though. There are some serious coupling that happens when these type of solutions are used, so it is usually not highly recommended, unless you are really in a dire need.

How to override instance/concrete class's method runtime? (e.g. reflection, cglib)

What I wanna do is a method that can
generate instance of Class X (a class variable passed in arg) and
override some of it's method
More specifically, the parent class X I want to override contains
Contains no default constructor (e.g. all constructors with args)
Constructors calling non-private method within the same class
Originally I thought it's quite simple to use reflection or something similar,
Then I found there's limitation on implementing my requirement.
For refection: Can only override "interface" via java.lang.reflect.Proxy
http://download.oracle.com/javase/1.3/docs/guide/reflection/proxy.html
for cglib: it cannot create instance of no default constructor and constructor calling non-private member methods
http://insufficientinformation.blogspot.com/2007/12/spring-dynamic-proxies-vs-cglib-proxies.html
I think this is achievable, since Mockito can do all kinds of method injection runtime.
Please anyone give some advise, Thanks.
The pseudo-code I image is like this:
createAndOverride(Class X) {
X newObj = X.newInstance(args) {
#override
methodOfX(args2) {
...
}
}
return newObj;
}
Original problem scenario
I was intended to test a Class which has several methods calling X1.get(), X2.get(), X3.get()
In some test case, I need to make Xn.get() to return something I can control for test (e.g. null)
Due to below constraint:
But due to mock tool restriction to JMock 1.0 (I have no control :( ), so I cannot just simply mock Xn.get() to returns "someSpecifiedObjects"
Xn has no null constructors and constructors calling non-private member
My workaround is self made Xn Class and pass them to test case to let Cn.get() to be expected
code example:
ClassToTest.SomeMethod(new X1() {
#override
get() {
return someSpecifiedObjects;
}
});
And this kind of thing is spread-ed over the Test Case.
Therefore, In order to reduce duplicate code, I would like to build a method to generate Xn instance with specified overrided method for test. e.g.
X1 x1 = createAndOverride(X1);
Then, the problem of this post comes
are you looking for something like javassist? You can instrument code and inject your methods at runtime. I personally try to avoid byte code manipulation as much as possible. Can you not have these overrides in your code base rather than doing on the fly? May be something like wrappers?
So what I think you need is a similar functionality to C#'s Reflection.Emit:
Using Reflection.Emit to create a class implementing an interface
Java Equivalent of Reflection.Emit
Dynamically Create Java Classes With JavaClassCreator
While I haven't done this myself, I think you should be able to use reflection/emission and dynamic type creation in order to achieve what you're looking for. However, I would still like to mention that if you're trying to test "functionality" that's not int he code path of the function you're testing, then you probably shouldn't be testing it at all. For example:
SomeObjectInterface get()
{
if(_someObjectStateIsSet)
{
// Return a concrete implementation A
return new ConcreteImplA();
}
else
{
// Return a concrete implementation B
return new ConcreteImplB();
}
}
In this case get has no code path that would return null, so you shouldn't need to test for null. I'm not sure if I understood your question 100% correctly, especially why you're testing for null, but consider the above advice and see what works for you.

Categories