I haven't done either of those things (as far as production code is concerned) here's a worked example which demonstrates this.
Here's the immutable, encapsulated, distinctly unsloppy domain model:
class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
Here's code that's only available for testing:
class MutablePerson extends Person {
private static final String DEFAULT_NAME = "Bob";
private static final int DEFAULE_AGE = 32;
public MutablePerson() {
super(DEFAULT_NAME, DEFAULT_AGE);
}
public MutablePerson withName(String name) {
return new MutablePerson(name, getAge());
}
public MutablePerson withAge(int age) {
return new MutablePerson(getName(), age);
}
private String getName() {
return accessor.get(this, "name", String.class);
}
private int getAge() {
return accessor.get(this, "age", Integer.class);
}
private final ReflectiveAccessor accessor = new ReflectiveAccessor();
}
Now it's true that the testing code has broken encapsulation but only as far as the testing code is concerned, not for the production code. The domain model itself is unchanged. It should be noted that there is a one-to-one relationship between the immutable domain model class and the mutable extension and that the break in encapsulation for a given domain model class propagates no further than the corresponding mutable extension; and again this break only exists in the testing code.
So I would say the testing code has a minor encapsulation breach which allows the testing code to have a more succinct form than possible with the test builder (it essentially removes the need for all the build() methods).
Unlike the Test Builder it would not be suitable to move the Mutable Extensions to the production code. Immutability & non-anemicness helps keep domain models from becoming 'bags-o-data', having a mutable version of each domain model in the production code would be too much of a temptation.