7

Like the title says, is it a bad practice to create/generate the Object.equals() method because I need it in my unit tests, but not in my regular code?

2
  • @KilianFoth in that question they're talking about modifying code, while I'm talking about actually adding pretty much 20~40 lines of code per domain object purely for JUnit.
    – Jelle
    Dec 5, 2016 at 12:09
  • Years later and I am using Kotlin now which generates these equals method in the background, which is a great help :-)
    – Jelle
    Jun 6, 2023 at 9:56

2 Answers 2

5

Writing code to make testing easier is a good thing. Writing code just for the tests to work around badly written code is bad.

If you are considering writing an equals() method because you need it in your unit tests, then this should set alarm bells going. Why do you need it? Tests should exercise the public APIs of your code. If those APIs do not expose classes with custom equals() then you shouldn't need to test those classes in that way.

So yes, it is bad practice to add functionality to the core code just for use by unit tests. You are just papering over the cracks when you do so. Instead fix the real problem, to remove the need for such extra code.

Update As the purpose of this code is not to access encapsulated values, but to test the equality of to objects bases on publicly accessible values, then equals() is good: just not on the domain objects themselves. Create the method in the test class/package (depending on scope needed) and have your tests call that.

10
  • This question was asked for a database test. What I wanted to achieve was something like: assertEquals(myProject, databaseProject);. Is it a good idea instead to assert each field seperately, like: assertEquals(myProject.getId(), databaseProject.getId());, which makes my test bigger, but does not affect the actual code?
    – Jelle
    Dec 5, 2016 at 12:24
  • @Jelle, would it, by any chance, make your test "20~40 lines" bigger? ;)
    – David Arno
    Dec 5, 2016 at 12:37
  • probably even more, since I have to do this for every time I want to assert...
    – Jelle
    Dec 5, 2016 at 12:38
  • serialise the object to a file and compare with a known good file
    – Ewan
    Dec 5, 2016 at 12:46
  • 2
    Sorry, overlooked your update, will remove my comment and downvote. Nevertheless I think adding an "equals" method to a domain object to make it more testable is nothing bad (as long as it is implemented correctly, and not sloppy because it is just "for testing").
    – Doc Brown
    Dec 5, 2016 at 13:53
0

Equality of objects in your unit tests is probably needed to verify results produced by production code. As public API of these results is all you want to check in tests , there is a simple, yet convenient way to perform same comparisons non-intrusively.

Create a descriptor class, that takes object in question as argument, inspects it's public API for interesting properties and makes them it's fields. Such descriptor is trivially constructible from field values and therefore could be used in tests easily:

class Descriptor {
    int field1;
    string field2;
    Descriptor(f1,f2){
        field1=f1;
        field2=f2;
    }
    Descriptor(IResult r) {
       this (r.getNumber (), r.getString ());
    }
    booolean equals(Descriptor d) {
       return field1.equals (d. field1) && field2.equals (d. field2);
    }

    string toString () {
       some test frameworks will be more helpful, provided with string representation of data under verification
    }
}


.....


 void test () {
     Descriptor  actual = new Descriptor (subject.produce ());
     Descriptor expected = new Descriptor (0, "Hello world!");
     assertEquals (expected, actual, "Should greet the world");
 }
0

Not the answer you're looking for? Browse other questions tagged or ask your own question.