The Robustness Principle (or Postel's Law) states

Be conservative in what you do, be liberal in what you accept from others (often reworded as "Be conservative in what you send, be liberal in what you accept").

This principle has some criticisms.

I realized this has interesting implications for mocks. Suppose you have

public class MyObj {
private final Integer x;

public MyObj(Integer x) {
if (x < 0) {
throw new IllegalArgumentException("negative x!");
}
this.x = x;
}

public int getX() {
return x;
}
}


In a unit test, we can have

MyObj myObj = mock(MyObj.class);
when(myObj.getX()).thenReturn(-1);


which bypasses our sanity checks!

My takeaways from this are:

Don't use mocks for POJO/data-ish objects!

If this feels painful, create a fixtures class:

public class MyObjFixtures {
@Inject Random random;

public MyObj create() {
return new MyObj(Math.abs(random.nextInt()));
}
}


Create "fake" implementations when possible/appropriate.

Usually, it's quite a bit easier to create a fake implementation than a real implementation:

1. use maps/lists instead of a real database
2. take shortcuts like avoiding concurrency where possible
3. depend on fakes of whatever API calls you need

There's some danger in this -- you should definitely consider wiring things up in a way that your tests can run against "real" implementations or sandboxes of them.

Another major concern becomes having a way to "reset" the fake implementations between tests to reduce flake, or coming up with a way to test that avoids the need to reset.