-3

Gradle is such an interesting build tool that it prompted me to look at Spock and JUnit -- which I've never done before. What is the basic workflow with TDD?

My approach has been to do frequent builds, slightly less frequent clean builds, and to run the application as much as possible. Certainly, there are entire books on TDD, but my most basic question is about the workflow.

Instead of working in src/main/java, most of the coding is done in the test directory? This, to me, intuitively, seems wrong. With version control, why have the duplicate directory structure? It can only lead to discrepancies between src/main and src/test which must be resolved manually.

Why not just work in one branch, then, when complete, create a branch without the tests?

What do you do when you want to actually run the application?

  • 3
    How does TDD, branching and java directory structure even relate? They are completely unrelated concepts. – Euphoric Feb 3 '16 at 11:48
  • jamesshore.com/Blog/Lets-Play is a very watchable demonstration of one approach to TDD on a real Java project. – Scroog1 Feb 3 '16 at 13:55
  • What do you want to accomplish by creating "a branch without tests"? – Doc Brown Feb 3 '16 at 14:20
  • "What do you do when you want to actually run the application?" You run it. Where you want to deploy it, you deploy without the tests. The tests are there for whilst you develop the code. They aren't used for running the application or for deploying it. – David Arno Feb 3 '16 at 17:46
6

The basic workflow for TDD is commonly known as "Red; Green; Refactor":

  1. Red: Write a failing test
  2. Green: Modify the code to make that test pass (without any existing tests failing)
  3. Refactor: Tidy up the code to better incorporate the change.

There are numerous resources that explain this process in details, eg The Cycles of TDD

It's unclear to me as to what the relevance of your comments re src/main and src/test and branches are to this process. However, regarding builds: you need to do a full build and re-run of all tests after each of the above three steps. The tests remain part of your source, always, as the whole idea is to re-run all tests after all changes to ensure you haven't broken an unrelated test (and thus feature) with a change.

  • For the green step, both the code in src/main and src/test must be modified. Class A in src/main is, or should be, exactly the same as Class A in src/test? Or, will there be differences, A and A prime? It seems a recipe for disaster. No? – Thufir Feb 3 '16 at 15:23
  • 2
    A and A prime usually contain completely different code.There is no fundamental reason to even have a 1:1 correspondence between the classes in src/main and those in src/test, that's only a common custom. In general, src/main/.../A will export methods like A.a() and A.b(), and then you'll often see corresponding methods src/test/.../A.test_a() and A.test_b(), but just as often the tests don't test individual methods but functionalities of A, and how to break them, like src/test/.../A.can_run_a_and_b(), or src/test/A.can_force_a_to_throw_an_exception(). – wallenborn Feb 3 '16 at 15:46
  • Method A.test_a() only exists in src/test -- that just seems like extra work to then remove that method from src/main. No pain no gain, ok, but that just seems like needless work. Thanks, though. – Thufir Feb 3 '16 at 22:34
  • @Thufir, No, no, no! A will never exist in src/test. You'll have a test class, A_Tests in src/test, which will have methods like wallenborn describes. src/main and src/test have completely different sets of code in them. – David Arno Feb 4 '16 at 13:54
3

You will normally keep your tests in a separate folder hierarchy as they usually aren't part of the binary you ship, and it's just simpler to not mix them up, but you keep them in the same repo and branch because they belong together in source.

As for where you work, TDD means Test Driven Development, which means you first write a (small) test for the feature you want your code to provide. You run it and watch it fail; red. You then implement the functionally in the "simplest possible way" until the test succeeds; green. You can then optionally refactor the code while keeping the test green. You then go back to writing another failing test, and so on.

By adding tests for additional features this way, and implementing the features in small increments, you reduce some of your guesswork that normally happens when you try to write the code before the tests. Tests in TDD represents a future user of your API, even before the code exists. Thus you're less likely to write code that's not needed, with a reasonable API, while constantly guarding any the code you've already written.

  • I can't get past the notion that while you don't ship the test directory, it's part of the main branch for the repo. That just strikes me as wrong. If it's in the main branch, then it should ship, otherwise it belongs in a different branch, to my thinking. I'll have to adapt. – Thufir Feb 4 '16 at 9:04
  • The repo contains all the things you need to build your product. It doesn't necessarily contain anything that is useful to your customers as is. And if you distribute it as source, there's no reason not to include the tests, just zip the whole repo. If you distribute compiled binaries with documentation baked into PDFs, why would you include any of the source content? For a middle way, if you're using c, you might distribute a compiled binary, but ship header files. – axl Feb 4 '16 at 13:38
2

The tests aren't there to ensure you write the code you want to write. They are there to ensure that three years from now, you don't accidentally change the way the code works through a seemingly unrelated change, causing unintelligible defects.

Tests are insurance against the future. Never remove the tests.

  • by this reasoning, if the code won't get used down the road, then tests wouldn't have utility. I thought that it was supposed to be a different mindset...? (no, I haven't read a book on testing yet) – Thufir Feb 3 '16 at 15:21
  • 1
    "Never" is too strong a term. If you have functionality that becomes unneeded later, then you remove that functionality, ensuring only the expected tests fail (to confirm the removal hasn't broken other features). Then those redundant tests can be removed. That's the only time you should remove tests though. – David Arno Feb 3 '16 at 17:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.