I previously mentioned that “Java For Testers” teaches Java without writing main
methods, and in fact uses @Test
annotated methods for all of its code.
I write tools like that, certainly for short lived tools that I might otherwise have to use a scripting language, or MVPs to try things out.
It is only after I have the basic MVP code, and then demonstrate the re-use value of the code (i.e. I re-use it enough to justify a GUI or command line interface) that I add a main
method.
In this post I’m going to give a quick example of what an MVP tool in an @Test
method looks like.
(skip to the bottom of the post if you want to watch a video of the approach in action.)
A few caveats before I start though:
- I am not putting this forward as ‘good’ code. It has taken me longer to write this blog post than it did to write the code.
- The code was designed to meet an immediate need
- I didn’t TDD this code. I wrote an MVP to solve a problem and I was reviewing, checking, running and testing as I went.
- with an MVP I often only add additional @Test methods when I refactor it and convert it for ongoing re-use
- I noticed a few extra methods on the
Files
,File
classes as I was building the code, so I experimented with those as I wrote the code, hence the mix of 1.5-1.8 code.
Since this was an MVP. I have a very specific task in mind. I’ll explain my usecase:
- I write my ‘books’ using leanpub
- I write a lot of my ongoing documentation in markdown generally
- I use online services like dillinger.io to format my local markdown into a pdf
- I use pandoc to create pdfs locally - particularly for client and consultancy reports
- I want the ability to switch between the leanpub tools and local markdown->pdf tools
- leanpub uses a Book.txt to create a list of files that it will process in sequence and convert into a book
- dillinger.io and pandoc prefer to work from a single file
I want to write a document ‘as though’ it were a leanpub document, with Book.txt, but have the ability to create a pdf locally.
All I really need to do that is to combine all the files listed in the Book.txt
file into a new leanpubpreview.md
file. And then process the new leanpubpreview.md
file in dillinger.io or pandoc.
I had a quick look on github to see if any other ’tools’ had already been created for this purpose.
I found:
Both of these are written in scripting languages (ruby, python).
I thought that I’d knock up something simple in Java rather than install Python or Ruby to try these scripts.
Since this was an MVP:
- I created a Java class called
LeanPubPandocPreviewTest
- I first wrote down my basic functional flow as a series of comments in a Java class.
// for given a hardcoded path to a Book.txt
// read the Book.txt file
// create a list of File names from Book.txt
// create a folder called pandoced (if necessary)
// create a new file in pandoced called leanpubpreview.md
// write all the contents of the files from Book.txt into this file
// output the command to generate the book to console
// note: this won't handle files with images at the moment
You can also see that I made a note of the limits of my experiment i.e. what it won’t do.
I then created an @Test
method to act as my GUI.
@Test
public void createPreviewMVP() throws IOException {
I then worked through each comment in my requirement spec and wrote the code for it.
e.g.
// for given a hardcoded path
String book_txt = "D:\\temp\\manuscript\\Book.txt";
// read the Book.txt file
File book_txt_file = new File(book_txt);
if(!book_txt_file.exists()){
throw new FileNotFoundException("Could not find file:"
+ book_txt_file.getAbsolutePath());
}
// create a list of File names from Book.txt
// experiment with the Java 1.8 readAllLines method
List<String> lines = Files.readAllLines(Paths.get(book_txt));
File book_txt_parent_folder = book_txt_file.getParentFile();
(You can see the rest of my adhoc code over on https://github.com/eviltester/pandocifier)
But…
- It’s not pretty.
- It’s not going to live long in that format.
- The use of comments suggests, at a minimum, that the code should be moved into methods.
But…
- it’s for me,
- to do a thing that I need done now, and fast.
Since I didn’t use TDD, the ’test strategy’ adopted was ‘build & check’. At the point that I wrote code that implemented each ‘comment’, I ran the @Test
method in debug mode to check it was doing what I expected it to.
I didn’t spend a lot of time working out the ‘best’ way to implement the comment. I just wrote the ‘first’ code that worked well enough.
This approach got me to the bottom of the requirement list, with code that did the job, and an output file that I could process via pandoc to ‘preview’ a ’leanpub’ project.
pandoc leanpubpreview.md -f markdown -s -o leanpubpreview.pdf --toc
I don’t normally release these type of MVP or adhoc tools to github. I normally have them on my local or xp-dev hosted repos.
But, for you, I’ve added this to Github so that you can see an example of using @Test
methods to create short lived, adhoc ’tools’.
And if I do continue to use this tool, and refactor it to make it live longer, then you’ll be able to see the evolution of the code on github.
The github repo is https://github.com/eviltester/pandocifier
PS. this blog post was drafted using Markdown, written in Evernote, and converted to HTML using dillinger.io and pasted into blogger.com