How much should I isolate my method for unit testing? - java

I have the following method:
public < V extends U > boolean matchesObject (V object, String filter) {
if (filterIsAny(filter)) return true;
else {
List<T> targets = getFilterTarget(object);
for (T t : targets) if (matches(t, filter)) return true;
return false;
}
}
where filterIsAny(filter) is a trivial method (just checks filter != null).
My question is: when I'm unit testing, is it worth to mock this method so that I'm sure that my function follows the correct path in the function, or do I just assume that my filterIsAny(filter) works and test using the real method? In this particular case, it is pretty easy to mock this method, but I have other instances where it would take several lines of code to mock intermediate results returned by trivial functions, such as list.indexOf(object) in a list of mocked objects.
I know it wouldn't be "pure" unit testing, since theoretically I'd be testing more than one function at a time, but how is is worth doing pure unit testing when it takes more work than finding the error in the code in the case of the test failing?

Assume that filterIsAny works until it gains non-trivial logic.
If your function is a wrapper for a single pure Java statement which has no logical branches, you can safely skip writing a unit test for it, and therefore only it in other unit tests. What you do want to test are the various branches in the method to be tested, assuming it has non-trivial logic.
Here, you would setup your filter object such that it produces a true and a false result when testing matchesObject(V object, String filter) based on the logical branch you're testing (no match in collection, one match in collection, invalid collection type (if possible), null input, etc.)
In your case, you can skip the filterIsAny(filter) evaluating to true branch, since you execute a trivial statement return true afterwards.
By the way, consider refactoring to Stream.anyMatch() if possible; it will reduce the number of return statements in your function and enhance readability.

Related

Mockito testing method void

I have a method called calculate
public class Calculator {
public void calc(int a, int b){
String condition = "first";
int result = 0;
if (condition.equals("first") {
condition = "no need";
else { result = a + b;}
after which the result is printed, whatever, i need to make a test on which i see if the value of condition was changed to "no need" or it remained "first", how can i check this using mockito testing? I tried so far, but i did not succeed. A good theoretical answer would be good, no need for code.
A good theoretical answer would be good
Mockito isn't a testing framework, it's a mocking framework.
You don't test things with Mockito, you just substitute behavior in dependencies, in order that you can test the behavior of your code under specific and otherwise hard-to-reproduce conditions.
So, the premise of the question is flawed, not simply because you're not using Mockito correctly, but also because you have no dependencies in this code for which behavior might be substituted.
But assuming you actually mean "how can I test this with a testing framework": you can't do that either.
Testing frameworks are just Java programs that run your Java program. They're not magic: all they can test for are return values, thrown exceptions, and side effects (e.g. log messages, things printed, changes of state).
The only things being changed here are local variables. You can't test anything about these because they are not observable outside the method in which they are defined.

What does removed call to "com.some.Filename::someMethodName" --> SURVIVED mean in pitest?

What does removed call to "com.some.Filename::someMethodName" --> SURVIVED mean in pitest.
Does it mean that if that method call is removed, the code will still work properly?
When pitest says the mutantion has survived it means it changed the codebase, and not a single test detected the code has changed. So you are not being very demanding on your test suite.
Ideally each mutation created should be killed by at least 1 unit test.
some more information regarding mutation test that may help you: https://pedrorijo.com/blog/intro-mutation/. (disclaimer, I'm the tutorial author)
Pi-Mutation wants:-
Every line of code got executed by unit test cases
And data being modified by the source code must asserted/validated.
Just master's these above two point's to be master of pi-mutation API.
Suppose you have following source code for which pi-mutation must be passed.
public Optional<CodeRemovedModel> method1(List<CodeRemovedModel> list) {
if(list.isEmpty()) {
return Optional.empty();
}
return doSomething(list);
}
private Optional<CodeRemovedModel> doSomething(List<CodeRemovedModel> list) {
// iterating over list item and modifying two fields.
// as per mutation this forEach loop must be executed
// And, the modified fields must be asserted - if not you will get "removed call .... -> SURVIVED" error
list.forEach(s -> {
s.setFirstName("RAHUL");
s.setLastName("VSK");
});
return Optional.of(list.get(0));
}
In following test case I'm ignoring assertion of one field, hence the error will shows up.
#Test
public void testMethod1_NON_EMPTY_LIST() {
List<CodeRemovedModel> l = new ArrayList<>();
l.add(new CodeRemovedModel());
Optional<CodeRemovedModel> actual = this.codeRemovedMutation.method1(l);
assertEquals("RAHUL", actual.get().getFirstName());
//assertEquals("VSK", actual.get().getLastName());
}
In Simple mutation testing terms:
Faults (or mutations) are automatically seeded into your code, then your tests are run. If your tests fail then the mutation is killed, if your tests pass then the mutation lived/survived.
In most cases, developers tend to write Unit Test cases targeting the Code coverage only which may not test each statement.So using a mutation testing tool like PIT is very helpful because it actually detects any faults in the executed code. But in most cases, to kill the mutants introduced by PIT, you have to write assert statements. Mutation testing improves the testing standard because it enforces to write test cases which tests each statement of the code.
Does it mean that if that method call is removed the code will still work properly?
It does not mean that when the method call is removed, the actual code will work but it means even the method call is removed, at least one of the test cases has not detected the change and the test case passed and mutant survived.

Mockito verify the last call on a mocked object

I have a bit of logic that needs to be tested such as:
{
...
A.add("1");
...
A.add("what ever");
...
A.add("2");
A.delete("5");
...
}
I have already mocked A in my test and I can test the add method is called once on argument ("2") such as:
Mockito.verify(mockedA).add("2");
My question is how can I test if I can verify the last call on method add is add("2") instead of other arguments.
Since the test above can't catch if somebody by accident adds another call such as add("3") in the last. Please notice that we don't care about other method invocations on A again afterwards. We also don't care about the times of the method called, the sequence of the methods called. The key point here is if we can verify the last true argument on a certain method of a certain mockedObject.
If you ask why do you need such functionality, I'd say in real world we might need to handle some logic that set something and the last set wins, and in order to avoid someone by accident set some other thing unexpected and I'd like to use our UT to catch this. And in order not to make the test too complex and neat, so I only expect to verify the last call on a certain method of a object instead verify something like order/noMoreInteractions/AtMostTimes and so on.
About the order of the invocations
By default, Mockito.verify() doesn't matter of the invocation order.
To take it into consideration, wrap the mock in an InOrder instance and perform the invocation verification on this instance.
About the no more interations
If the mock is no more invoked after the methods that you want to verify, you could use Mockito.verifyNoMoreInteractions(Object... mocks) that checks if any of given mocks has any unverified interaction such as :
InOrder inOrder = Mockito.inOrder(mockedA);
inOrder.verify(mockedA).add("1");
inOrder.verify(mockedA).add("2");
Mockito.verifyNoMoreInteractions(mockedA);
If the mock may still be invoked after the methods that you want to verify, you could add after your verifies an invocation to verify(T mock, VerificationMode mode) by passing a VerificationMode that checks that at most 2 invocations were performed.
InOrder inOrder = Mockito.inOrder(mockedA);
inOrder.verify(mockedA).add("1");
inOrder.verify(mockedA).add("2");
Mockito.verify(mockedA, Mockito.atMost(2)).add(Mockito.anyString());
A warning about your think and this way of mocking
Since the test above can't catch if somebody by accident adds another
call such as add("3") in the last.
Mockito provides a powerful and broad toolkit to work with mocks. Some features such as verify and more particularly verify that no more interaction was detected about a mock or a specific method of the mock make your test more complex to read and to maintain.
As well as, currently you want to check that the invocations on a mock were performed in a specific order. But you generally want to use these checks only as required that is according to the business/logic scenarios, not technical invocations.
For example supposing that in the tested method you have a case where for business reasons the mocked method is invoked 3 times and another case where the mocked method is invoked 2 times. It could make sense to check that it is only invoked 2 times and not more in the case with two expected invocations.
But in a general way, you should be cautious that your unit test doesn't overuse mocking verify that could look like as a assertion on the description of the flow and not a assertion on the behavior/logic.
Thanks #staszko032, inspired by the ArgumentCaptor, instead of getAllValues and verify the sequence, we can use getValue of captor since captor's getValue always get the last true argument. We can do it like this:
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
Mockito.verify(mockedA, Mockito.atLeastOnce()).add(captor.capture());
Assert.assertEquals("2", captor.getValue());
What this looks like to me is that you are mocking a data class. In my experience it's better to leave (stateful) data classes and mock (stateless) services. This way, you can verify that the method under test produces the correct data, rather than just verifying a series of invocations. Along with testdata builders (making it easy to instantiate your data classes with some default state, using builder pattern for instance), it becomes real easy to write tests.
If you do need to mock, the only way to test what you want is to use InOrder, and verify each of the invocations on the mock, and end with verifyNoMoreInteractions.
I've ended up implementing a new VerificationMode to do this. Here's the code in case it's useful to anyone.
class MostRecently implements VerificationMode {
#Override
public void verify(VerificationData data) {
MatchableInvocation target = data.getTarget();
List<Invocation> invocations = data.getAllInvocations();
if (invocations.isEmpty()) {
throw wantedButNotInvoked(target);
}
List<Invocation> targets = findInvocations(invocations, target);
if (targets.isEmpty()) {
throw wantedButNotInvoked(target);
}
Invocation lastInvocation = invocations.get(invocations.size() - 1);
if (target.matches(lastInvocation)) {
return;
}
ListIterator<Invocation> iterator = invocations.listIterator(invocations.size());
Invocation previous = iterator.previous();
Invocation undesired = previous;
while (!target.matches(previous)) {
undesired = previous;
previous = iterator.previous();
}
Invocation lastGoodInvocation = previous;
throw new MockitoAssertionError(join(
"Wanted most recent on '" + lastGoodInvocation.getMock() + "' to be " + lastGoodInvocation.getMethod(),
"No more interactions wanted after " + lastGoodInvocation.getLocation(),
"but found this interaction on mock '"
+ MockUtil.getMockName(undesired.getMock()) + "':",
undesired.getLocation(),
allLocations(invocations)));
}
static String allLocations(List<Invocation> invocations) {
StringBuilder sb = new StringBuilder("***\nFor your reference, here is the list of all invocations.\n");
int counter = 0;
for (Invocation i : invocations) {
sb.append(++counter).append(". ");
sb.append(i.getLocation()).append("\n");
}
return sb.toString();
}
}

How to unit test to the case where there are two public methods, one calling another?

What is the way to test the methods when there are two public methods and a method calls another public method in the same class?
How should I write unit tests in this scenario?
An example
class SpecificIntMath {
public int add(int a,int b) {
return a+b;
}
public int multiply(int a, int b) {
int mul = 0;
for(int i = 0;i<b,i++) {
mul=add(a,mul);
}
return mul;
}
}
This example doesn't show the complexity of both the methods involved but the concept.
Should I test add and multiply separately? If I should test multiply only, I feel like we miss out cases where multiple cannot provide parameters.
Assuming multiply and add to be tested separately, should I be able to mock add? How is that possible?
Assuming multiply and add to be tested separately and I shouldn't mock, should I let add perform as it is. If this is the case how should I deal with the flow of the program inside add?
What is the approach to test such a kind of situation.
Edit 1:
In the below code,
class MCVC {
public boolean getWhereFrom(List<User> users) {
boolean allDone = true;
for(User user: users){
String url = user.getUrl();
switch(url) {
case Consts.GOOGLE:
someDao.updateFromAddr(user);
user.setEntry("Search Engine");
break;
case Consts.FACEBOOK:
someDao.updateFromAddr(user);
user.setEntry("Social Media");
break;
case Consts.HOME:
someDao.updateToAddr(user);
user.setEntry("Company");
default
user.setEntry(null);
allDone = false;
break;
}
}
return allDone;
}
public void likedDeck() {
List<Users> usersList = deckDao.getPotentialUsers(345L,HttpStatus.OK);
boolean flag = getWhereFrom(usersList);
if(flag) {
for(User user: usersList) {
//some Action
}
}
}
}
Should I consider getWhereFrom() while testing likedDeck() or should I assume any default situation? If I consider default situation, I lose out on cases where the output isn't default. I am not sure I should mock it since class which is calling is being tested. Spying/Mocking class under test
You don't care.
You use unit-testing to test the contract of each public method on its own. Thus you write tests that make sure that both add() and multiply() do what they are supposed to do.
The fact that the one uses the other internally is of no interest on the outside. Your tests should neither know nor care about this internal implementation detail.
And just for the record: as your code is written right now; you absolutely do not turn to mocking here. Mocking is not required here; and only adds the risk of testing something that has nothing to do with your real production code. You only use mocking for situations when you have to control aspects of objects in order to enable testing. But nothing in your example code needs mocking to be tested. And if it would - it would be an indication of poor design/implementation (given the contract of those methods)!
Edit; given the changes example in the question:
First of all, there is a bug in getWhereFrom() - you iterate a list; but you keep overwriting the return value in that list. So when the first iteration sets the result to false; that information might be lost in the next loop.
I see two options for the actual question:
You turn to Mockito; and its "spy" concept to do partial mocking; in case you want to keep your source code as is
Me, personally; I would rather invest time into improving the production code. It looks to me as getWhereFrom() could be worth its own class (where I would probably not have it work on a list of users; but just one user; that also helps with returning a single boolean value ;-). And when you do that, you can use dependency injection to acquire a (mocked) instance of that "WhereFromService" class.
In other words: the code you are showing could be reworked/refactored; for example to more clearly follow the SRP. But that is of course a larger undertaking; that you need to discuss with the people around you.
At least test them both seperatly. That the multiply test implicitly tests the add is no problem. In most of this cases you should ask yourself the question if it is necessary that both methods need to be public.
Should I test add and multiply separately?
You should test them separately, if you are doing unit testing. You would only like to test them together when doing component or integration tests.
Assuming multiply and add to be tested separately, should I be able to
mock add?
yes
How is that possible?
use mockito or any other mocking framework. Exactly how you can see here Use Mockito to mock some methods but not others
Assuming multiply and add to be tested separately and I shouldn't
mock, should I let add perform as it is.
I wouldn't do that. Internal changes in add could affect the tests from multiply and your tests would get more complicated and unstable.

Using both junit assertions and mockito verification

I'm using Junit in conjunction with Mockito. I used mockito's verify method + junit assertion to do complete verification. Is this not desirable? Should we use one or the other but not both?
There's nothing wrong with using both.
Mockito's verify is used to assert a method was called (with the expected arguments) on the given mock.
JUnit's assertXYZ is used to assert that some result has the expected value.
Both are valid verifications, and if both are relevant, both should be used.
For example, consider the following (admittedly artificial) situation:
You have an interface that performs some mathematical calculation:
public interface ValueProducer {
public int getValue(int val);
}
And a class that doubles any result produced by it:
public class Doubler {
public static int doubleThatResult (ValueProducer producer, int val) {
return 2 * producer.getValue(val);
}
}
Testing it would require to assert two things:
That getValue was properly called
That the result is doubled
So, e.g.:
public class DoublerTest {
#Test
public void testDoubleThatResult() throws Exception {
int value = 7; // Or any other value
int returnMock = 13; // Or any other value
ValueProducer producerMock = mock(ValueProducer.class);
when(producerMock.getValue(value)).thenReturn(returnMock);
int actual = Doubler.doubleThatResult(producerMock, value);
verify(producerMock);
assertEquals(26, actual);
}
}
Mureinik's answer is absolutely correct—assertions and verifications are complementary, and work quite well together—but doing both for a single behavior may be redundant.
The goal is usually to express the test in the most flexible and implementation-agnostic way possible. State testing (with assertions) is often the most appropriate choice, in that sense: it doesn't matter which methods were called as long as the resulting state is correct. A Mockito verification, while possible, may introduce brittleness (where the code behaves correctly but the test is broken). Mockito itself warns of this in verify(T)'s Javadoc and the linked article by Mockito's creator Szczepan Faber.
This redundancy is certainly not the worst thing: It does test a property of the system, and may be a worthwhile endeavor in testing interactions with sensitive, legacy, third-party, or frequently-changing dependencies. If the interaction is unimportant, though, these extra verifications may come at the expense of brittleness.
Other times, confirming correct behavior means testing side-effects—for example, ensuring that someSystem.reset() was called, or testing a cache by verifying a provider was NOT called. These are perfect examples for verification, because the interaction with the external service is critical testable behavior. In some of these cases, Mockito verifications are the only way to make the correct assertions.
Many test cases are a combination of the above, so feel free to use assertions and verifications freely together; just remember that state testing is often sufficient and preferable.

Categories