How to test Comparator for JUnit test? - java

I need to test the compare() method and i am confused on how. Can I see how to do this?
public class MemberComparator implements Comparator<Member> {
private final String clientId;
public MemberComparator(String clientId) {
this.clientId = clientId;
}
#Override
public int compare(Member m1, Member m2) {
if (m1.getClientId().startsWith(clientId)) {
return m2.getClientId().startsWith(clientId) ? m1.getClientId().compareTo(m2.getClientId())
: -1;
} else {
return m2.getClientId().startsWith(clientId) ? 1
: m1.getClientId().compareTo(m2.getClientId());
}
}
}
So far, this is what i have created in my test. How can i get this to work? What should i do as this way isn't working, assuming i do not change the current approach to MemberComparator class.
class MemberComparatorTest {
//private MemberComparator caseID_test;
//private final MemberComparator memberComparator = new MemberComparator("jake");
#Test
void testEqual() {
Member m1 = new Member();
Member m2 = new Member();
int result = memberComparator.compare(m1,m2);
//assertTrue("expected to be equal", result == 0);
}
}

There are two questions you'd need to answer when writing a Comparator:
Does it meet the requirements of the Comparator interface?
Does it do what you need?
The first one is reasonably hard to write tests for; I'd argue it's better to write something using a "known good" pattern, in order to help you reason about its correctness from the code.
In the case of Comparator, the "known good" pattern is something that you see from the chaining methods:
// This boolean comparison may be the wrong way round, I never remember which way is which. If so, reverse it.
Comparator.comparing(m -> m.getClientId().startsWith(clientId))
.thenComparing(Member::getClientId)
You compare the first thing, and return if they're different; you compare the second thing, and return if they're different, etc.
You could use the code above if you're using Java 8+: this gives a totally fine Comparator. If you can't use this (for whatever reason), your compare method could be rewritten as:
int compareSw = Boolean.compare(m1.getClientId().startsWith(clientId), m2.getClientId().startsWith(clientId));
if (compareSw != 0) {
return compareSw;
}
return m1.getClientId().compareTo(m2.getClientId());
Because this follows the "known good" pattern, this can be seen to meet the requirements of the Comparator interface by inspection.
(Of course, you have to be careful about thinking "Looks Good To Me!", because you might miss something, e.g. using m1.getClientId() twice instead of both m1.getClientId() and m2.getClientId(). But that sort of defect would be caught by sufficient testing of the following).
Then it's just a matter of testing to make sure it does what you want: that is, if you take two Members, does this Comparator order them the way you want? That's an easy test to write, without getting bogged down in the details of the Comparator.
List<Member> members = List.of(m1, m2);
assertEquals(m1, Collections.min(members, comparator)); // For example.
assertEquals(m2, Collections.max(members, comparator)); // For example.

Some assertions might look like:
assertTrue(comparator.compare(m1, m1) == 0);
assertTrue(comparator.compare(m1, m2) > 0);
assertTrue(comparator.compare(m2, m1) < 0);

Related

How do I assert equality on two classes without an equals method?

Say I have a class with no equals() method, to which do not have the source. I want to assert equality on two instances of that class.
I can do multiple asserts:
assertEquals(obj1.getFieldA(), obj2.getFieldA());
assertEquals(obj1.getFieldB(), obj2.getFieldB());
assertEquals(obj1.getFieldC(), obj2.getFieldC());
...
I don't like this solution because I don't get the full equality picture if an early assert fails.
I can manually compare on my own and track the result:
String errorStr = "";
if(!obj1.getFieldA().equals(obj2.getFieldA())) {
errorStr += "expected: " + obj1.getFieldA() + ", actual: " + obj2.getFieldA() + "\n";
}
if(!obj1.getFieldB().equals(obj2.getFieldB())) {
errorStr += "expected: " + obj1.getFieldB() + ", actual: " + obj2.getFieldB() + "\n";
}
...
assertEquals("", errorStr);
This gives me the full equality picture, but is clunky (and I haven't even accounted for possible null problems). A third option is to use Comparator, but compareTo() will not tell me which fields failed equality.
Is there a better practice to get what I want from the object, without subclassing and overridding equals (ugh)?
There is many correct answers here, but I would like to add my version too. This is based on Assertj.
import static org.assertj.core.api.Assertions.assertThat;
public class TestClass {
public void test() {
// do the actual test
assertThat(actualObject)
.isEqualToComparingFieldByFieldRecursively(expectedObject);
}
}
UPDATE: In assertj v3.13.2 this method is deprecated as pointed out by Woodz in comment. Current recommendation is
public class TestClass {
public void test() {
// do the actual test
assertThat(actualObject)
.usingRecursiveComparison()
.isEqualTo(expectedObject);
}
}
Mockito offers a reflection-matcher:
For latest version of Mockito use:
Assert.assertTrue(new ReflectionEquals(expected, excludeFields).matches(actual));
For older versions use:
Assert.assertThat(actual, new ReflectionEquals(expected, excludeFields));
I generally implement this usecase using org.apache.commons.lang3.builder.EqualsBuilder
Assert.assertTrue(EqualsBuilder.reflectionEquals(expected,actual));
I know it's a bit old, but I hope it helps.
I run into the same problem that you, so, after investigation, I found few similar questions than this one, and, after finding the solution, I'm answering the same in those, since I thought it could to help others.
The most voted answer (not the one picked by the author) of this similar question, is the most suitable solution for you.
Basically, it consist on using the library called Unitils.
This is the use:
User user1 = new User(1, "John", "Doe");
User user2 = new User(1, "John", "Doe");
assertReflectionEquals(user1, user2);
Which will pass even if the class User doesn't implement equals(). You can see more examples and a really cool assert called assertLenientEquals in their tutorial.
If you're using hamcrest for your asserts (assertThat) and don't want to pull in additional test libs, then you can use SamePropertyValuesAs.samePropertyValuesAs to assert items that don't have an overridden equals method.
The upside is that you don't have to pull in yet another test framework and it'll give a useful error when the assert fails (expected: field=<value> but was field=<something else>) instead of expected: true but was false if you use something like EqualsBuilder.reflectionEquals().
The downside is that it is a shallow compare and there's no option for excluding fields (like there is in EqualsBuilder), so you'll have to work around nested objects (e.g. remove them and compare them independently).
Best Case:
import static org.hamcrest.beans.SamePropertyValuesAs.samePropertyValuesAs;
...
assertThat(actual, is(samePropertyValuesAs(expected)));
Ugly Case:
import static org.hamcrest.beans.SamePropertyValuesAs.samePropertyValuesAs;
...
SomeClass expected = buildExpected();
SomeClass actual = sut.doSomething();
assertThat(actual.getSubObject(), is(samePropertyValuesAs(expected.getSubObject())));
expected.setSubObject(null);
actual.setSubObject(null);
assertThat(actual, is(samePropertyValuesAs(expected)));
So, pick your poison. Additional framework (e.g. Unitils), unhelpful error (e.g. EqualsBuilder), or shallow compare (hamcrest).
You can use Apache commons lang ReflectionToStringBuilder
You can either specify the attributes you want to test one by one, or better, exclude those you don't want:
String s = new ReflectionToStringBuilder(o, ToStringStyle.SHORT_PREFIX_STYLE)
.setExcludeFieldNames(new String[] { "foo", "bar" }).toString()
You then compare the two strings as normal. For the point about reflection being slow, I assume this is only for testing, so shouldn't be so important.
Since this question is old, I will suggest another modern approach using JUnit 5.
I don't like this solution because I don't get the full equality picture if an early assert fails.
With JUnit 5, there is a method called Assertions.assertAll() which will allow you to group all assertions in your test together and it will execute each one and output any failed assertions at the end. This means that any assertions that fail first will not stop the execution of latter assertions.
assertAll("Test obj1 with obj2 equality",
() -> assertEquals(obj1.getFieldA(), obj2.getFieldA()),
() -> assertEquals(obj1.getFieldB(), obj2.getFieldB()),
() -> assertEquals(obj1.getFieldC(), obj2.getFieldC()));
The library Hamcrest 1.3 Utility Matchers has a special matcher that uses reflection instead of equals.
assertThat(obj1, reflectEquals(obj2));
Some of the reflection compare methods are shallow
Another option is to convert the object to a json and compare the strings.
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public static String getJsonString(Object obj) {
try {
ObjectMapper objectMapper = new ObjectMapper();
return bjectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
} catch (JsonProcessingException e) {
LOGGER.error("Error parsing log entry", e);
return null;
}
}
...
assertEquals(getJsonString(MyexpectedObject), getJsonString(MyActualObject))
AssertJ assertions can be used to compare the values without #equals method properly overridden, e.g.:
import static org.assertj.core.api.Assertions.assertThat;
// ...
assertThat(actual)
.usingRecursiveComparison()
.isEqualTo(expected);
Using Shazamcrest, you can do:
assertThat(obj1, sameBeanAs(obj2));
Compare field-by-field:
assertNotNull("Object 1 is null", obj1);
assertNotNull("Object 2 is null", obj2);
assertEquals("Field A differs", obj1.getFieldA(), obj2.getFieldA());
assertEquals("Field B differs", obj1.getFieldB(), obj2.getFieldB());
...
assertEquals("Objects are not equal.", obj1, obj2);
You can use reflection to "automate" the full equality testing. you can implement the equality "tracking" code you wrote for a single field, then use reflection to run that test on all fields in the object.
In case you just need flat fields comparison you can use AssertJ
Assertions.assertThat(actual)).isEqualToComparingFieldByField(expected);
This is a generic compare method , that compares two objects of a same class for its values of it fields(keep in mind those are accessible by get method)
public static <T> void compare(T a, T b) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
AssertionError error = null;
Class A = a.getClass();
Class B = a.getClass();
for (Method mA : A.getDeclaredMethods()) {
if (mA.getName().startsWith("get")) {
Method mB = B.getMethod(mA.getName(),null );
try {
Assert.assertEquals("Not Matched = ",mA.invoke(a),mB.invoke(b));
}catch (AssertionError e){
if(error==null){
error = new AssertionError(e);
}
else {
error.addSuppressed(e);
}
}
}
}
if(error!=null){
throw error ;
}
}
I stumbled on a very similar case.
I wanted to compare on a test that an object had the same attribute values as another one, but methods like is(), refEq(), etc wouldn't work for reasons like my object having a null value in its id attribute.
So this was the solution I found (well, a coworker found):
import static org.apache.commons.lang.builder.CompareToBuilder.reflectionCompare;
assertThat(reflectionCompare(expectedObject, actualObject, new String[]{"fields","to","be","excluded"}), is(0));
If the value obtained from reflectionCompare is 0, it means they are equal. If it is -1 or 1, they differ on some attribute.
In common case with AssertJ you can create custom comparator strategy:
assertThat(frodo).usingComparator(raceComparator).isEqualTo(sam)
assertThat(fellowshipOfTheRing).usingElementComparator(raceComparator).contains(sauron);
Using a custom comparison strategy in assertions
AssertJ examples
I had the exact same conundrum when unit testing an Android app, and the easiest solution I came up with was simply to use Gson to convert my actual and expected value objects into json and compare them as strings.
String actual = new Gson().toJson( myObj.getValues() );
String expected = new Gson().toJson( new MyValues(true,1) );
assertEquals(expected, actual);
The advantages of this over manually comparing field-by-field is that you compare all your fields, so even if you later on add a new field to your class it will get automatically tested, as compared to if you were using a bunch of assertEquals() on all the fields, which would then need to be updated if you add more fields to your class.
jUnit also displays the strings for you so you can directly see where they differ. Not sure how reliable the field ordering by Gson is though, that could be a potential problem.
I tried all the answers and nothing really worked for me.
So I've created my own method that compares simple java objects without going deep into nested structures...
Method returns null if all fields match or string containing mismatch details.
Only properties that have a getter method are compared.
How to use
assertNull(TestUtils.diff(obj1,obj2,ignore_field1, ignore_field2));
Sample output if there is a mismatch
Output shows property names and respective values of compared objects
alert_id(1:2), city(Moscow:London)
Code (Java 8 and above):
public static String diff(Object x1, Object x2, String ... ignored) throws Exception{
final StringBuilder response = new StringBuilder();
for (Method m:Arrays.stream(x1.getClass().getMethods()).filter(m->m.getName().startsWith("get")
&& m.getParameterCount()==0).collect(toList())){
final String field = m.getName().substring(3).toLowerCase();
if (Arrays.stream(ignored).map(x->x.toLowerCase()).noneMatch(ignoredField->ignoredField.equals(field))){
Object v1 = m.invoke(x1);
Object v2 = m.invoke(x2);
if ( (v1!=null && !v1.equals(v2)) || (v2!=null && !v2.equals(v1))){
response.append(field).append("(").append(v1).append(":").append(v2).append(")").append(", ");
}
}
}
return response.length()==0?null:response.substring(0,response.length()-2);
}
For Unit testing I just serialize the object to a JSON string and compare it.
For example with Gson:
import com.google.gson.GsonBuilder
import junit.framework.TestCase.assertEquals
class AssertEqualContent {
companion object {
val gson = GsonBuilder().create()
fun assertEqualContent(message: String?, expected: Any?, actual: Any?) {
assertEquals(message, gson.toJson(expected), gson.toJson(actual))
}
}
}
As the expected and actual object is supposed to be of the same type the field order will be the same.
Pros:
You will get a nice string comparison highligting exactly where the difference is.
No extra libraries (provided that you have a JSON library already)
Cons:
Objects of different types might produce the same JSON (but if they do, you might consider why do you have different classes for the same data.... and how they could end up being compared in a testing method :-)
Can you put the comparision code you posted into some static utility method?
public static String findDifference(Type obj1, Type obj2) {
String difference = "";
if (obj1.getFieldA() == null && obj2.getFieldA() != null
|| !obj1.getFieldA().equals(obj2.getFieldA())) {
difference += "Difference at field A:" + "obj1 - "
+ obj1.getFieldA() + ", obj2 - " + obj2.getFieldA();
}
if (obj1.getFieldB() == null && obj2.getFieldB() != null
|| !obj1.getFieldB().equals(obj2.getFieldB())) {
difference += "Difference at field B:" + "obj1 - "
+ obj1.getFieldB() + ", obj2 - " + obj2.getFieldB();
// (...)
}
return difference;
}
Than you can use this method in JUnit like this:
assertEquals("Objects aren't equal", "", findDifferences(obj1, obj));
which isn't clunky and gives you full information about differences, if they exist (through not exactly in normal form of assertEqual but you get all the info so it should be good).
From your comments to other answers, I don't understand what you want.
Just for the sake of discussion, lets say that the the class did override the equals method.
So your UT will look something like:
SomeType expected = // bla
SomeType actual = // bli
Assert.assertEquals(expected, actual).
And you are done. Moreover, you can not get the "full equality picture" if the assertion fails.
From what I understand, you are saying that even if the type did override equals, you would not be interested in it, since you want to get the "full equality picture". So there is no point in extending and overriding equals either.
So you have to options: either compare property by property, using reflection or hard-coded checks, I would suggest the latter. Or: compare human readable representations of these objects.
For example, you can create a helper class that serializes the type you wish tocompare to an XML document and than compare the resulting XML! in this case, you can visually see what exactly is equal and what is not.
This approach will give you the opportunity to look at the full picture but it is also relatively cumbersome (and a little error prone at first).
You can override the equals method of the class like:
#Override
public int hashCode() {
int hash = 0;
hash += (app != null ? app.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
HubRule other = (HubRule) object;
if (this.app.equals(other.app)) {
boolean operatorHubList = false;
if (other.operator != null ? this.operator != null ? this.operator
.equals(other.operator) : false : true) {
operatorHubList = true;
}
if (operatorHubList) {
return true;
} else {
return false;
}
} else {
return false;
}
}
Well, if you want to compare two object from a class you must implement in some way the equals and the hash code method

Is there a way to test for enum value in a list of candidates? (Java)

This is a simplified example. I have this enum declaration as follows:
public enum ELogLevel {
None,
Debug,
Info,
Error
}
I have this code in another class:
if ((CLog._logLevel == ELogLevel.Info) || (CLog._logLevel == ELogLevel.Debug) || (CLog._logLevel == ELogLevel.Error)) {
System.out.println(formatMessage(message));
}
My question is if there is a way to shorten the test. Ideally i would like somethign to the tune of (this is borrowed from Pascal/Delphi):
if (CLog._logLevel in [ELogLevel.Info, ELogLevel.Debug, ELogLevel.Error])
Instead of the long list of comparisons. Is there such a thing in Java, or maybe a way to achieve it? I am using a trivial example, my intention is to find out if there is a pattern so I can do these types of tests with enum value lists of many more elements.
EDIT: It looks like EnumSet is the closest thing to what I want. The Naïve way of implementing it is via something like:
if (EnumSet.of(ELogLevel.Info, ELogLevel.Debug, ELogLevel.Error).contains(CLog._logLevel))
But under benchmarking, this performs two orders of magnitude slower than the long if/then statement, I guess because the EnumSet is being instantiated every time it runs. This is a problem only for code that runs very often, and even then it's a very minor problem, since over 100M iterations we are talking about 7ms vs 450ms on my box; a very minimal amount of time either way.
What I settled on for code that runs very often is to pre-instantiate the EnumSet in a static variable, and use that instance in the loop, which cuts down the runtime back down to a much more palatable 9ms over 100M iterations.
So it looks like we have a winner! Thanks guys for your quick replies.
what you want is an enum set
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/EnumSet.html
put the elements you want to test for in the set, and then use the Set method contains().
import java.util.EnumSet;
public class EnumSetExample
{
enum Level { NONE, DEBUG, INFO, ERROR };
public static void main(String[] args)
{
EnumSet<Level> subset = EnumSet.of(Level.DEBUG, Level.INFO);
for(Level currentLevel : EnumSet.allOf(Level.class))
{
if (subset.contains(currentLevel))
{
System.out.println("we have " + currentLevel.toString());
}
else
{
System.out.println("we don't have " + currentLevel.toString());
}
}
}
}
There's no way to do it concisely in Java. The closest you can come is to dump the values in a set and call contains(). An EnumSet is probably most efficient in your case. You can shorted the set initialization a little using the double brace idiom, though this has the drawback of creating a new inner class each time you use it, and hence increases the memory usage slightly.
In general, logging levels are implemented as integers:
public static int LEVEL_NONE = 0;
public static int LEVEL_DEBUG = 1;
public static int LEVEL_INFO = 2;
public static int LEVEL_ERROR = 3;
and then you can test for severity using simple comparisons:
if (Clog._loglevel >= LEVEL_DEBUG) {
// log
}
You could use a list of required levels, ie:
List<ELogLevel> levels = Lists.newArrayList(ELogLevel.Info,
ELogLevel.Debug, ELogLevel.Error);
if (levels.contains(CLog._logLevel)) {
//
}

How to refactor a method to make it easier to test

Below is a method that I'm having a hard time figuring out how to test using JUnit.
This method is difficult to test because it depends on the results of other methods (e.g. getClosestDcoumentCode).
Based on my reading of JUnit, this suggests I should refactor the method. But how? And if refactoring is not necessary, how do you test a method that depends on other methods?
Thank you,
Elliott
private static String findPrincipal(List<DocumentKey> documentkeys_) {
Hashtable<String, Integer> codecounts = new Hashtable<String, Integer>();
for (DocumentKey document : documentkeys_) {
int x = 0;
String closestCode = getClosestDocumentCode(document.candidates);
if (closestCode == null) continue;
int thecount = 0;
if (codecounts.containsKey(closestCode))
thecount = codecounts.get(closestCode);
if (document.hasKey)
thecount += 2;
else
thecount++;
codecounts.put(closestCode, new Integer(thecount));
x++;
}
String closestCode = getClosestCode(codecounts);
return closestCode;
}
Well, first of all, I wonder if the method really needs to be static, and what that class is doing. It looks like it might be a GOD class, or at the very least it's violating the single responsibility principle. What does getClosestCode do? If it was a class, you could inject it with a stub in your tests into the test class.
EasyMock will let you mock the method response, but I'm not sure how you mock static methods.
In general, you probably need to
Extract long functions into classes
Make functionality non-static
Maintain the single responsibility principal
It sounds to me like getClosestCode and getClosestDocumentCode belong to a different set of responsibilities than the findPrincipal method. So you'll want to begin by separating these into two different classes. Create an interface for each class to implement. The class that implements the findPrincipal method can then rely on the other interface as a constructor argument, like this:
public class PrincipalFinderImpl implements PrincipalFinder
{
private CodeFinder codeFinder;
public PrincipalFinderImpl(CodeFinder codeFinder) {
this.codeFinder = codeFinder;
}
public String findPrincipal(List<DocumentKey> documentkeys_) {
Hashtable<String, Integer> codecounts = new Hashtable<String, Integer>();
for (DocumentKey document : documentkeys_) {
int x = 0;
String closestCode = codeFinder.getClosestDocumentCode(document.candidates);
if (closestCode == null) continue;
int thecount = 0;
if (codecounts.containsKey(closestCode))
thecount = codecounts.get(closestCode);
if (document.hasKey)
thecount += 2;
else
thecount++;
codecounts.put(closestCode, new Integer(thecount));
x++;
}
String closestCode = codeFinder.getClosestCode(codecounts);
return closestCode;
}
}
Now it should be easy to create another class the implements the CodeFinder interface, either manually or using a Mocking framework. You can then control the results of each call to getClosestCode and getClosestDocumentCode, and ensure that each of these methods gets called with exactly the arguments you expect it to be called with.
I don't read the method deeply. But if a private method needs to test, it indicates something wrong with your design. At least Kent Beck thinks so.
There is a chapter on stub calls on JUnit Second Edition, i recommend you have a look at that if you think your existing codes are not written to test-driven development standards.

Creating method filters

In my code I have a List<Person>. Attributes to the objects in this list may include something along the lines of:
ID
First Name
Last Name
In a part of my application, I will be allowing the user to search for a specific person by using any combination of those three values. At the moment, I have a switch statement simply checking which fields are filled out, and calling the method designated for that combination of values.
i.e.:
switch typeOfSearch
if 0, lookById()
if 1, lookByIdAndName()
if 2, lookByFirstName()
and so on. There are actually 7 different types.
This makes me have one method for each statement. Is this a 'good' way to do this? Is there a way that I should use a parameter or some sort of 'filter'? It may not make a difference, but I'm coding this in Java.
You can do something more elgant with maps and interfaces. Try this for example,
interface LookUp{
lookUpBy(HttpRequest req);
}
Map<Integer, LookUp> map = new HashMap<Integer, LookUp>();
map.put(0, new LookUpById());
map.put(1, new LookUpByIdAndName());
...
in your controller then you can do
int type = Integer.parseInt(request.getParameter(type));
Person person = map.get(type).lookUpBy(request);
This way you can quickly look up the method with a map. Of course you can also use a long switch but I feel this is more manageable.
If good means "the language does it for me", no.
If good means 'readable', I would define in Person a method match() that returns true if the object matches your search criteria. Also, probably is a good way to create a method Criteria where you can encapsulate the criteria of search (which fields are you looking for and which value) and pass it to match(Criteria criteria).
This way of doing quickly becomes unmanageable, since the number of combinations quickly becomes huge.
Create a PersonFilter class having all the possible query parameters, and visit each person of the list :
private class PersonFilter {
private String id;
private String firstName;
private String lastName;
// constructor omitted
public boolean accept(Person p) {
if (this.id != null && !this.id.equals(p.getId()) {
return false;
}
if (this.firstName != null && !this.firstName.equals(p.getFirstName()) {
return false;
}
if (this.lastName != null && !this.lastName.equals(p.getLastName()) {
return false;
}
return true;
}
}
The filtering is now implemented by
public List<Person> filter(List<Person> list, PersonFilter filter) {
List<Person> result = new ArrayList<Person>();
for (Person p : list) {
if (filter.accept(p) {
result.add(p);
}
}
return result;
}
At some point you should take a look at something like Lucene which will give you the best scalability, manageability and performance for this type of searching. Not knowing the amount of data your dealing with I only recommend this for a longer term solution with a larger set of objects to search with. It's an amazing tool!

Verifying partially ordered method invocations in JMockit

I'm trying to write a unit test (using JMockit) that verifies that methods are called according to a partial order. The specific use case is ensuring that certain operations are called inside a transaction, but more generally I want to verify something like this:
Method beginTransaction is called.
Methods operation1 through to operationN are called in any order.
Method endTransaction is called.
Method someOtherOperation is called some time before, during or after the transaction.
The Expectations and Verifications APIs don't seem to be able to handle this requirement.
If I have a #Mocked BusinessObject bo I can verify that the right methods are called (in any order) with this:
new Verifications() {{
bo.beginTransaction();
bo.endTransaction();
bo.operation1();
bo.operation2();
bo.someOtherOperation();
}};
optionally making it a FullVerifications to check that there are no other side-effects.
To check the ordering constraints I can do something like this:
new VerificationsInOrder() {{
bo.beginTransaction();
unverifiedInvocations();
bo.endTransaction();
}};
but this does not handle the someOtherOperation case. I can't replace the unverifiedInvocations with bo.operation1(); bo.operation2() because that puts a total ordering on the invocations. A correct implementation of the business method could call bo.operation2(); bo.operation1().
If I make it:
new VerificationsInOrder() {{
unverifiedInvocations();
bo.beginTransaction();
unverifiedInvocations();
bo.endTransaction();
unverifiedInvocations();
}};
then I get a "No unverified invocations left" failure when someOtherOperation is called before the transaction. Trying bo.someOtherOperation(); minTimes = 0 also doesn't work.
So: Is there a clean way to specify partial ordering requirements on method calls using the Expectations/Verifications API in JMockIt? Or do I have to use a MockClass and manually keep track of invocations, a la:
#MockClass(realClass = BusinessObject.class)
public class MockBO {
private boolean op1Called = false;
private boolean op2Called = false;
private boolean beginCalled = false;
#Mock(invocations = 1)
public void operation1() {
op1Called = true;
}
#Mock(invocations = 1)
public void operation2() {
op2Called = true;
}
#Mock(invocations = 1)
public void someOtherOperation() {}
#Mock(invocations = 1)
public void beginTransaction() {
assertFalse(op1Called);
assertFalse(op2Called);
beginCalled = true;
}
#Mock(invocations = 1)
public void endTransaction() {
assertTrue(beginCalled);
assertTrue(op1Called);
assertTrue(op2Called);
}
}
if you really need such test then: don't use mocking library but create your own mock with state inside that can simply check the correct order of methods.
but testing order of invocations is usually a bad sign. my advice would be: don't test it, refactor. you should test your logic and results rather than a sequence of invocations. check if side effects are correct (database content, services interaction etc). if you test the sequence then your test is basically exact copy of your production code. so what's the added value of such test? and such test is also very fragile (as any duplication).
maybe you should make your code looks like that:
beginTransaction()
doTransactionalStuff()
endTransaction()
doNonTransactionalStuff()
From my usage of jmockit, I believe the answer is no even in the latest version 1.49.
You can implement this type of advanced verification using a MockUp extension with some internal fields to keep track of which functions get called, when, and in what order.
For example, I implemented a simple MockUp to track method call counts. The purpose of this example is real, for where the Verifications and Expectations times fields did not work when mocking a ThreadGroup (useful for other sensitive types as well):
public class CalledCheckMockUp<T> extends MockUp<T>
{
private Map<String, Boolean> calledMap = Maps.newHashMap();
private Map<String, AtomicInteger> calledCountMap = Maps.newHashMap();
public void markAsCalled(String methodCalled)
{
if (methodCalled == null)
{
Log.logWarning("Caller attempted to mark a method string" +
" that is null as called, this is surely" +
" either a logic error or an unhandled edge" +
" case.");
}
else
{
calledMap.put(methodCalled, Boolean.TRUE);
calledCountMap.putIfAbsent(methodCalled, new AtomicInteger()).
incrementAndGet();
}
}
public int methodCallCount(String method)
{
return calledCountMap.putIfAbsent(method, new AtomicInteger()).get();
}
public boolean wasMethodCalled(String method)
{
if (method == null)
{
Log.logWarning("Caller attempted to mark a method string" +
" that is null as called, this is surely" +
" either a logic error or an unhandled edge" +
" case.");
return false;
}
return calledMap.containsKey(method) ? calledMap.get(method) :
Boolean.FALSE;
}
}
With usage like the following, where cut1 is a dynamic proxy type that wraps an actual ThreadGroup:
String methodId = "activeCount";
CalledCheckMockUp<ThreadGroup> calledChecker = new CalledCheckMockUp<ThreadGroup>()
{
#Mock
public int activeCount()
{
markAsCalled(methodId);
return active;
}
};
. . .
int callCount = 0;
int activeCount = cut1.activeCount();
callCount += 1;
Assertions.assertTrue(calledChecker.wasMethodCalled(methodId));
Assertions.assertEquals(callCount, calledChecker.methodCallCount(methodId));
I know question is old and this example doesn't fit OP's use case exactly, but hoping it may help guide others to a potential solution that come looking (or the OP, god-forbid this is still unsolved for an important use case, which is unlikely).
Given the complexity of what OP is trying to do, it may help to override the $advice method in your custom MockUp to ease differentiating and recording method calls. Docs here: Applying AOP-style advice.

Categories