On Thu, Aug 29, 2019 at 1:02 AM Krinkle <krinklem...@gmail.com> wrote:
> What did you want to assert in this test?

In a proper unit test, I want to completely replace all non-value
classes with mocks, so that they don't call the actual class' code.
This way I can test the class under test without making assumptions
about other classes' behavior.

This is not possible at all if any method is declared final. As soon
as the class under test calls a final method, you cannot mock the
object. This is without any use of expects() or with() -- even just
method()->willReturn().

> I find there is sometimes a tendency for a test to needlessly duplicate the
> source code by being too strict on expecting exactly which method is called
> to the point that it becomes nothing but a more verbose version of the
> source code; always requiring a change to both.
>
> Personally, I prefer a style of testing where it providers a simpler view
> of the code. More like a manual of how it should be used, and what
> observable outcome it should produce.

The idea of good unit tests is to allow refactoring without having to
worry too much that you're accidentally changing observable behavior
in an undesired way. Ideally, then, any observable behavior should be
tested. Changes in source code that don't affect observable behavior
will never necessitate a change to a test, as long as the test doesn't
cheat with TestingAccessWrapper or such.

This includes tests for corner cases where the original behavior was
never considered or intended. This is obviously less important to test
than basic functionality, but in practice, callers often accidentally
depend on all sorts of incidental implementation details. Thus
ideally, they should be tested. If the test needs to be updated, that
means that some caller somewhere might break, and that should be taken
into consideration.

On Thu, Aug 29, 2019 at 1:12 AM Aaron Schulz <aschulz4...@gmail.com> wrote:
> Interfaces will not work well for protected methods that need
> to be overriden and called by an abstract base class.

If you have an interface that the class implements, then it's possible
to mock the interface instead of the class, and the final method
problem goes away. Of course, your "final" is then not very useful if
someone implements the interface instead of extending the class, but
that shouldn't happen if your base class has a lot of code that
subclasses need.

On Thu, Aug 29, 2019 at 10:37 AM Daniel Kinzler <dkinz...@wikimedia.org> wrote:
> Narrow interfaces help with that. If we had for instance a cache interface 
> that
> defined just the get() and set() methods, and that's all the code needs, then 
> we
> can just provide a mock for that interface, and we wouldn't have to worry 
> about
> WANObjectCache or its final methods at all.

Any interface would solve the problem, even if it was just a copy of
all the public methods of WANObjectCache. That would be inelegant, but
another possible solution if we want to keep using final.

_______________________________________________
Wikitech-l mailing list
Wikitech-l@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/wikitech-l

Reply via email to