Let me revive this question as I'm going through a similar thing recently. Here are a few thoughts...
As it's needed for tests perhaps a comparison by equals would do instead of checking/setting fields directly?
Pattern worth considering if the alternative is de-encapsulation. I mean, if there is no need to touch these fields in prod code ideally they shouldn't need being touched in tests either.
Entity would have own fields based equals and hashCode implemented.
Lombok's @EqualsAndHashCode annotation can help with reducing the boilerplate.
Test goes then like expect: new Entity(id) == new Entity(id) (assuming there is such constructor).
If equality is not the way to go package scope might give better encapsulation with an appropriate package structure (main/src/java):
package foo.bar
public class Entity {
Long id
}
Control over the id access is more flexible now and independent from the test code. While User extends Entity can have no access to the id if placed in a different package, the test code can have a class accessing it, like for example (src/test/groovy):
package foo.bar
class EntityAccess {
private final Entity entity
EntityAccess(Entity entity) {
this.entity = entity
}
static EntityAccess access(Entity entity) {
new EntityAccess(entity)
}
Long getId() {
entity.id
}
void setId(Long id) {
entity.id = id
}
}
I'm sure the boilerplate can be reduced with some fancy Groovy AST annotations. The point is prod code can keep the fields hidden while in tests, with a static import for EntityAccess.access, a field can be accessed without any Groovy hax0rs:
given: access(entity).id = 5 to set or expect: access(entity).id == 5 to assert on entity's id.
If possible though, I would've rather kept both the Entity and User immutable and tested by equality without altering the objects state.