0

I just googled "Joshua Bloch TDD"... not much came up, which is a huge shame because I'd really like to know what he's got to say on the matter.

Item 13 (I'm looking at the 2nd edition) is entitled "Minimize the accessibility of classes and members". After a couple of pages he says:

To facilitate testing, you may be tempted to make a class, interface or member* more accessible. ... It is acceptable to make a private member of a public class package-private in order to test it, but it is not acceptable to raise the accessibility any higher than that... Luckily, it isn't necessary either, as tests can be made to run as part of the package being tested, thus gaining access to its package-private elements.

* by "members" he means "fields, methods, nested classes and nested interfaces".

As a TDD newb, but gradually finding my feet, I am aware that the current consensus seems to be not to include testing classes with the app code packages, nor even to have a matching structure under src\test and src\main: mostly TDD experts readily seem to structure their testing directories in other ways (e.g. you have one directory called "unittests" another called "functionaltests" and another called "e2etests").

Specifically, I have followed the TDD development of the auction app in "Growing Object Oriented Software Guided by Tests". The author there has no qualms about adding hundreds of public methods. Furthermore, after one chapter I looked at the downloaded "structure so far" and he had completely changed the testing directory structure to divide things into categories of test...

Is there any seasoned TDD hand out there who has, at least in the past, found this to be a source of dilemma? If so, how have you resolved it?

As a practical example, I'm cutting my teeth on TDD techniques by developing a Lucene index app: it indexes documents and then lets you query them. At the current time all the app classes are in the same package. The only method which actually needs to be public is main in one class. And yet, of course, I have many, many public methods: they could all be package-private were it not for the fact that I am using TDD.

PS no tag for "method-visibility" so I chose "class-visibility"

later

It appears that I may have been led down a rather unfortunate path by the approach taken in "Growing Object-Oriented...", where the over-use of public methods was presumably used just because it's a demonstration of the technique. Ha.

If you want to split your categories of tests, does anyone ever use this sort of approach:

\src\unit_tests\java\core\MainTest.java

but also, for example:
\src\func_tests\java\core\MainTest.java
and
\src\e2e_tests\java\core\MainTest.java?

mike rodent
  • 14,126
  • 11
  • 103
  • 157
  • "not to include testing classes with the app code packages" you mean e.g. gradles `src/main/java/com/foo` vs `src/test/java/com/foo`? In which case classes are in the same package but not in the same directory. – zapl Dec 11 '16 at 18:42
  • Ah... sorry, of course: this had temporarily slipped my mind because I've been emulating what others do... I shall edit my question. Is this how you resolve the "dilemma"? – mike rodent Dec 11 '16 at 18:44
  • @mikerodent What is the "dilemma", exactly? – lexicore Dec 11 '16 at 18:48
  • Please see edit to my question: a lot ot TDD practitioners seem to use a non-symmetrical directory structure for their testing packages and classes... which surely necessarily means that some app methods must be made public just for testing purposes. – mike rodent Dec 11 '16 at 18:49
  • @mikerodent "which surely necessarily means that some app methods must be made public just for testing purposes" - not surely. Using different directories does not disallow you package-private access. Using different packages does. Same package does not necessarily mean same directory. – lexicore Dec 11 '16 at 18:55
  • Thanks... not sure I totally understand: if I have an app class `\src\main\java\core\Main.java` and a structure like this for unit testing: `\src\test\java\alltests\unittests\MainTest.java` ... how can `MainTest` ever access package-private methods in `Main`? – mike rodent Dec 11 '16 at 19:01

2 Answers2

1

as tests can be made to run as part of the package being tested

This does not mean that you have to put your tests in the same directory as main classes, they just have to be in the same package which can very well be separate directory.

Assume you have a package com.acme.foo. So your directory structure may be:

src
  main
    java
      com
        acme
          foo
            MainClass
  test
    java
      com
        acme
          foo
            MainClassTest

MainClassTest is in the same package as MainClass so it has access to package-private stuff. But these are separate directories, so your resulting JAR will not contain MainClassTest.

lexicore
  • 42,748
  • 17
  • 132
  • 221
  • Thanks. Sorry, yes, this had slipped my mind! Please see my edit to my question. Do you stick to this pattern yourself? – mike rodent Dec 11 '16 at 18:47
  • @mikerodent Simple answer is yes. But we also have separater projects for integration tests, we do a lot of BDD (Cucumber) with separate directory structures etc. But we definitely don't make stuff `public` just for tests sake. – lexicore Dec 11 '16 at 18:51
  • Thanks... if I understand you correctly, therefore, at the moment it would be impossible for me to do integration tests between my different classes because they are all in the same package and, as I say, I don't need any public methods at all. As a newb the whole area of integration tests is a bit of a mystery: would it be right that you only do integration tests **between different packages**? – mike rodent Dec 11 '16 at 18:54
  • @mikerodent In integration tests we test several components in integration. Whatever the definition of the component is. In the current project our components are microservices so we start a bunch of them in the integration test environment and play a set of Cucumber "features" against them. But it's not "one size fits all", it is hard to deliver a universal truth here. – lexicore Dec 11 '16 at 18:59
0

I am not sure how this works in Gradle, as I am using Maven, but I imagine the concepts there are similar. Therefore I will explain it with Maven in mind. The typical setup in a Maven project looks like this:

enter image description here

On the root level of the projects there is src and target. Into the target folder everything goes that is created during the build process. This means that src contains the sources of our actual project. Under src there are two other directories: main and test. Simply put into main goes everything that will end up in the productive code, that will be delivered. The test directory contains the test code for the main tree.

Therefore it is usual that the same package hierarchy from the src/main/java directory is also present in src/test/java and therefore for a test class with the same package definition will have access to all members of the producive class which resides in the main branch.

hotzst
  • 7,238
  • 9
  • 41
  • 64
  • Yes, thanks, it is exactly the same in Gradle. It's just that TDD projects sometimes seem to depart from this symmetrical directory structure, meaning that they can't take advantage of package-private access. – mike rodent Dec 11 '16 at 18:57