During most of my tenure at Google, I taught the Developer Testing course to nearly all the engineering nooglers in the NYC office, and as well as some other east coast offices and engineers visiting from Australia.
At Etsy, I spend a fair amount of time actually thinking about developer testing in addition to developer happiness and ways to increase developer throughput.
Test-Driven Development is a possible development workflow that incorporates Developer Testing, but Developer Testing does not necessarily only exist in Test-Driven Development (TDD).
TDD is a development style with a development cycle:
- Add a tests for the new functionality
- Run all tests and see that the new tests FAIL
- Implement the new functionality
- Run all tests and see that the new tests PASS
- Refactor code
- Repeat
Thinking about it, it’s kind of like a re-wording for the Waterfall Development Model
But I don’t think that is the issue.
Recently someone asked me about TDD, and I spoke of my hesitancy towards the idea. I told him that the whole notion of having to test first was too harsh.
He, being a believer in TDD being the way to go, was skeptical that relaxing the test first constraint would be a bad thing. But the reality is, those who can test first and work well with test first will test first no matter what, but those who cannot test first because they are overwhelmed, inexperienced, or just plan do not think that way, they will likely not test or not produce.
So he took it further, and tried to argue about inside-out versus outside-in. The notion being that if you code the implementation first and then the test (inside-out) then you will code the implementation the easiest way possible for you and the test will be difficult because it is playing second fiddle. If you code the test first and the implementation second (outside-in) then you will implement the tests against an easy to use interface, and the implementation will be written to fulfill the easy to use interface.
I honestly do see the point on inside-out versus outside-in, but you can achieve the simple to use interfaces while testing second. You just have to remember one thing:
Tests should always be treated like every other consumer of the subject under test.
In short for now, that means that if you find yourself doing something tricky in your test to work around the interface of the the subject under test (SUT), you should fix the interface of the SUT and not do something tricky in your test. Your test is a consumer just like any other object that consumes the SUT in your production code, and if it is difficult to consume it in a test, then it will be difficult to consume it in production.
Getting back to the real point at hand, Developer Testing versus TDD. It is really important that as a developer you practice some sort of developer testing.
It could be manually testing your code, but if you manually test just remember that you should write down your manual tests. Writing out the tests is a good form of communication. It will allow other developers to know what they should be testing for when they begin to play in that area of the code.
It could be an automated functional test, which is like writing down a manual test case only better because it is executable. The only warning on these is that they have many points of failure. If you decide to incorporate these into a continuous deploy environment, you will want to consider either running them as probers or alerts through something like nagios, and not as red/green tests.
It could be xUnit tests, which can be either integration tests or unit tests. Integration tests give piece of mind that the actual implementations of collaborating object work together, and unit tests allow for small, fast, nimble, deterministic tests that ensure that the logic in the individual functions are correct while testing against the interface of the collaborators. Integration tests should generally be treated with the same care as automated functional tests, as discussed above. Unit tests are great for being red/green tests in a deployment pipeline.
We could dive into more about all these ways of testing, but the main point being: as a developer it is important that you test. If you write code, throw the code over the proverbial wall, wait for a response from a tester, fix, and repeat you will waste a lot of time. You will really be doing Waterfall Development. The other thing you will lose is the opportunity to communicate what you have accomplished and how you interpreted the requirements. You will miss out on executable documentation, whether by human (manual) or machine (automated).
Do a favor for yourself and all your peers, subscribe to developer testing. There are many ways to do it.