Tests too far away from code

In the maven directory structure the source files are under one directory structure, and the tests are in a different data structure somewhere else. Does anyone else find this annoying? It would be great if I could keep my tests next to my code.

Has anyone figure out a way around this problem? I know the maven directory structure is sort of imposed on us as Scala users, and sometimes we don’t really have a choice.

I haven’t used Maven with Scala, but you should be able to set the source root for the test files: http://maven.apache.org/ref/3.3.3//maven-model/maven.html#class_build
I don’t know if it will work, if testSourceDirectory is the same as sourceDirectory, but it’s worth a try.

Personally, I don’t like tests and sources in the same source root. That way all the test classes are visible to the main source code, and when packaging the software, the tests will always be included (which also means more classes on the classpath for the user and larger packages).

2 Likes

Yes, I see the problem of having too many classes in the path.

BTW, I’m not using maven directly. It’s just that scala projects seem to assume the maven directory structure. At least sbt seems to assume it as well as IntelliJ. Such assumptions as directory names match package names, and file names match class names–something which I have always found annoying and problematic and unintuitive.

Such assumptions as directory names match package names, and file names match class names–something which I have always found annoying and problematic and unintuitive.

May I ask why do you find those unintuitive?
BTW, in Scala (at difference than in Java) you do not have to follow those.
I find them very intuitive most of the time, but I sometimes use a different filename if I believe it makes sense (usually because there are many classes / tratis / objects in the same file)

About the tests part.
I also do not have any problems with them being on different source folders.
And since usually tests classes are in the same package of their main classes, matching them is quite easy for me.

Nevertheless, I would like to put in the table two alternatives I have heard.

  1. Having the tests on a different file but in the same folder as the main files, but with a different extension which allows the compiler or packager to exclude them from the generated artifacts.

  2. Having the tests as methods / functions in the same file.
    But the language has a test reserved word which allows the compiler or packager to remove all those functions when building.

It may be interesting to work with those two alternatives for a while. But my first impression is that those would feel very coupled.
For example, sometimes you need custom logic for your tests, or you want to share a couple of stubs into many tests.

3 Likes

In Scala you can ignore all those conventions, and everything will keep working. The src/main/scala and src/test/scala stuff however is the directory structure that sbt uses by default. You can configure it to use a different structure. You can probably even configure sbt to use all files that end in -test.scala as test sources and all other files as main sources. However I personally have no clue how to configure that.

2 Likes

Ah, other people typed faster than me, so I’ll just add, that for sbt you should also be able to change the paths, see: https://www.scala-sbt.org/1.x/docs/Howto-Customizing-Paths.html
(Again, i’ve not tried what happens if Test and Compile paths are the same)

1 Like

Normally, SBT compiles the main code first before it compiles the test code. I find this useful, because if I introduce a change that breaks compilation, it makes sense to fix the main code first.

Yes, it has been my experience that scala does not enforce these conventions. I usually name files what makes sense. Until now it hasn’t hurt anything, although IntelliJ highlights and warns about file-name mismatches.

I found it more unintuitive at first, as I regularly changed package names within files in order to make things visible where I wanted them to be visible. It didn’t cross my mind that I might need to create a directory in the file system with a corresponding name, nor that I’d need to change the directory name if I changed a package name.

The use model I was using was that I was teaching a course to students. I have homework lecture material in one directory, exercise solutions in one directory, templates for students to start with lots of ??? in another directory, and test cases in another directory. So my directory structure intuitively matches the intent of the file (lecture/template/homework), not the package names, and file names correspond to lecture number or homework exercise number, not class/object names.

matches the intent of the file (lecture/template/homework)

It feels that you want modules instead of packages.

perhaps, tell me more. Can code from one module extend code in another?

Yes, you can make one module depend on another.


and file names correspond to lecture number or homework exercise number, not class/object names.

This feels like a very particular use case, most of the time you would have named things instead of numbered things.
And it makes sense that if you are looking for a scala.collection.immutable.List you may search it in scala/collection/immutable/List.scala

Also, I do not find myself changing packages names that often.
It is like a design / decision you make at the beginning and you try it to make right the first time.


(sorry, I hit send before finishing)

perhaps, tell me more. Can code from one module extend code in another?

I edited my previous comment since I sent it by mistake.
I also answered your question there.

1 Like

If you don’t want src/main and src/test to be separate, you can point Compile / scalaSource and Test / scalaSource to the same directory and configure Compile / unmanagedSources / excludeFilter and Test / unmanagedSources / excludeFilter to include/exclude the files you want/don’t.

(At least, I worked on an sbt project that was configured this way, some years ago. I assume it would still work with a modern sbt version.)

I can understand from a TDD perspective that for example starting tests next to code could help to re-enforce testing based practices. Writing tests first, etc. I wonder if without changing the layout some editor magic could make for a satisfying experience.

1 Like

Yes, in fact I use this quite a bit for that reason. In Intellij, the Packages project view merges the source directories for each project into one view.

When we used TDD the whole team started to work on functions/classes in the test files, and later extracted to the final destination.

Sometimes IntelliJ can jump to the test file (the project I have opened up has not this feature right now, no idea why). And also ctrl/cmd+clicking (cmd+b on mac with keyboard only) the function name will show your usages (in tests too).