3

I have a basic unit test (for the sample) that involves this code:

void testShouldCreateACar() {
  Car car = someone.createFerrari();
  assertTrue(car.name == "Ferrari"); // can't access name since name is private
}

I can't access name since there's not a getter in Car (or Ferrari) class for it.
I don't want to create getters only for unit testing purpose.

Note that the SUT is out of the Car's package (distinct package).
Note also that the Ferrari's constructor is private (creation only accessible through createFerrari() method on someone.

What is a good practice to achieve this assertion?

8
  • 10
    You don't. You want to test the public interface, the behaviour of your unit. Not internal and implementation details. If its internal name is not available to the user, then there's no reason to create a test for it because it's not part of the behaviour of your class. Jun 15, 2016 at 13:55
  • So you would expect a specific unit test of Ferrari (or Car) to validate fields?
    – Mik378
    Jun 15, 2016 at 13:56
  • @VincentSavard Please see my comment on the kai's answer below.
    – Mik378
    Jun 15, 2016 at 14:10
  • 2
    @Mik378: he is saying that things that are purely internal to your class should not be validated. Test the behaviour of your class, not the implementation. You want to be able to freely refactor the internal behaviour of your class and use the tests to make sure the behaviour stays the same, tests that break when the implementation changes are counterproductive. Jun 15, 2016 at 14:10
  • 3
    I see that, but if the value of the field never matters for your class's behavior, then it doesn't even need to be persisted. If it does matter for the behavior, then test the behavior. Jun 15, 2016 at 14:12

2 Answers 2

8

If it is the case that the name of the car isn't publicly available in any way at all, then it makes no sense to test it, because obviously it doesn't matter to any client code. If the name of the car matters, even if you can't actually see it by inspecting the field, then exercise some method that relies on the name being correct and assert against some visible result from that.

Edit following clarifying comment: If your ORM cares about private fields, I'd say this would be much more beneficial to test indirectly via integration tests. I probably wouldn't go as far as writing specific tests for all fields of all classes though, seems too granular for me. I'd recommend just writing some integration tests that require persistance to work at all, and you'll get the reflection checked implicitly.

3
  • It would matter for an ORM that persists further the entity through reflection of private fields. I wanted to check that the creation of the object is well made before persistence step. Otherwise, if there is a bug with the persistence (odd field's content insterted), it would be harder to guess where the error comes from: from creation of the object itself or from some mutations afterwards.
    – Mik378
    Jun 15, 2016 at 14:08
  • 2
    It sounds, then, that you are wanting to test the ORM code's handling of reflection, not the specific object's private fields. If you really do want to test e.g. Car, then your test code might persist the Car instance with your ORM code, then directly query the persisted data and verify/validate that data.
    – Castaglia
    Jun 15, 2016 at 15:02
  • 1
    @Mik378 See my update
    – sara
    Jun 15, 2016 at 20:05
0

Change the scope of the field.

If the name matters and that behavior should be tested, then make that field public. In this case, make it public read only. Then one will be able to test the state of the object after the constructor is fired.

1
  • 1
    Good code is testable, this is true, but good tests don't rely on private implementation details. You don't wanna "ruin" your api by exposing a bunch of things that don't matter to clients, and indeed will just make your classes harder to use and understand. Exposing state for others to query goes right against good OOP design and encapsulation.
    – sara
    Jun 15, 2016 at 20:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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