Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

My sense is that one should make the unit tests to be as resilient as possible to refactoring and changes. This means that for so long as the public behavior of the class does not change, one should not need to do much if any updates to the tests.

Thus any test that is written in such a way that it would be present an issue in refactoring code should be avoided if at all possible. A simple example is directly constructing the class under test in the test method:

  @Test 
  public void tryToAvoidDoingThis() {
     MyClass = new MyClass(param1, param2);
     // do stuff to my class
   }
If this is done for each test method, when the constructor parameters change, e.g. a new one is added, then each of the constructors calls in the test method(s) will have to be updated.

Instead, have a level of indirection and have a single method that can create a sample MyClass. Now when the parameters change, only one construction site has to be updated.

In general, unit tests should not be testing specific / internal implementation details of the class. Rather, the tests should verify the documented public behavior of the class.



That's the crux of good tests. That they test the unchanging interface between parts of code, without enforcing no change in implementation.

Interestingly it's also the crux of good design. Breaking code up into composeable pieces that aren't braided together.


There's an inconsistency here: unit tests should depend only on the public behavior of a class; the constructor is public; constructor calls should nevertheless be avoided where possible.


Factoring out a common constructor in tests is an example of making the tests resilient against changes in the underlying code. If the constructor changes, the tests need to be fixed in one place, not in 50.

Other examples may be around a `setup` method. If the method is private, don't test it. Then you can refactor freely. If it's public, test the pre/post conditions around the method in as few places as possible (hopefully one). Even if other tests rely on the object having been "setup", just trust that it works. If the specification of `setup` changes, you just have the `setup` tests to update, not the entire object.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: