Created
September 4, 2012 00:20
-
-
Save brianstorti/3615231 to your computer and use it in GitHub Desktop.
Growing object-oriented software, guided by tests
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Levels of testing | |
Acceptance: Does the whole system work? | |
We use acceptance tests to help us, with the domain experts, understand and agree on what we are going to build next. We also use them do make sure that | |
we haven't broken any existing features as we continue developing. Our preferred implementation of the "role" of acceptance testing is to write end-to-end | |
tests which, as we just noted, should be as end-to-end as possible; our bias often leads us to use these terms interchangeably although, in some cases, | |
acceptance tests might not be end-to-end. | |
Integration: Does our code work against code we can't change? | |
We use the term integration tests to refer to the tests that check how some of our code works with code from outside the team that we can't change. It might | |
be a public framework such as a persistence mapper, or a library from another team within our organization. The distinction is that integration tests make | |
sure that any abstractions we build over third-party code work as we expect. | |
Unit: Do our objects do the right thing, are they convenient to work with? | |
Unit tests give us a great feedback about the internal quality of our code, while acceptance tests tell us more about the external quality. Integration | |
tests are in the middle. | |
Tell, don't ask / Law of Demeter | |
We have objects sending each other messages, so what do they say? Out experience is that the calling object should describe what it wants in terms of the | |
role that its neighbor plays, and let the called object decide how to make that happen. Objects make their decisions based only on the information they | |
hold internally or that which came with the triggering message; they avoid navigating to other objets to make thins happen. Followed consistently, this | |
style produces more flexible code because it's easy to swap objects that play the same role. | |
As well as hiding information, there's a more subtle benefit from "Tell, Don't Ask". It forces us to make explicit and so name the interactions between | |
objects, rather then leaving them implicit in the chain of getters. | |
"We find that the effort of writing a test first also gives us rapid feedback about the quality of our design ideas - that making code accessible for testing | |
often drives it towards being cleaner and more modular" | |
"When we find a feature that's difficult to test, we don't just ask ourselves how to test it, but also why is it difficult o test." | |
"If you write bad unit tests, you might find that you gain none of the benefits, and instead are stuck with a bunch of tests that are time consuming an hard | |
to maintain." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment