Monday, 5 December 2016

Let's Code - Binary Chopifier - Just Enough Code and Tooling to Start

TLDR; “Let’s code a Binary Chopifier” which I plan, code as prototype to plan in an @Test method, test interactively, experiment, and release as an @Test.




I want to create a few more examples of “Java in Action” and I’m doing that in some YouTube videos and blog posts that I think of as “Let’s Code”. First up is “Let’s code a Binary Chopifier” which I plan, prototype to plan, test interactively, experiment, and release to Github.

Let’s code a Binary Chopifier



When I was recording - Let’s Explore Google Search I made a note to write a binary chopifier.

https://www.youtube.com/watch?v=b3izXqERlqo

In this series of videos we are going to create the binary chopifier and add it to Test Tool Hub.

Plan

First thing I did was make notes on what I wanted to support me in testing:

    Tool idea: binary chopper!
    start: 1024 end: 2048
    result

    chop: value (inc)
-------------------
        01: 1536  (512)
        02: 1792 (256)
        03: 1920 (128)
        04: 1984 (64)
        05: 2016 (32)
        06: 2032 (16)
        07: 2040 (8)
        08: 2044 (4)
        09: 2046 (2)
        10: 2047 (1)
        11: 2048 (0)

Explaining Binary Chop:
  • I try a value of length 2048
  • System doesn’t accept it because it is too long
  • I want to find the limit
  • I try 1024 (I binary chop 2048) and if that is accepted then
  • I try 1536 (midway between 1024 and 2048), and if that is accepted then
  • etc. until I narrow down on the value that is the limit
And if you watch the video you’ll see my mental arithmetic process was quite slow. I could spend the time boosting my mental arithmetic, or I could write a tool to help me.

Guess which is easier?

So I write a tool.

Thinking through an algorithm

The plan above represents a basic output to support me as the tester.

Really all I want is the chop and the value, but I used inc to help me calculate the chops
  • So I calculate the difference between the start and end: 1024
  • Divide it by 2 (chop) to get 512 then I add that to start (inc) and get 1536
  • And keep going.

Start by writing a ‘@Test’ which does this

I start by writing an @Test method which implements this algorithm and I can see if it works or not

@Test
public void calculateBinaryChopForStartAndEndFromThoughtAlgorithm(){

  int start = 1024;
  int end = 2048;
  int choppoint=start;
  int inc = start;

  while(inc > 0){

  inc = (end-choppoint)/2;
  choppoint=choppoint+inc;
  System.out.println(String.format("%d (%d)", choppoint, inc));
  }

}

Which gives me the output

1536 (512)
1792 (256)
1920 (128)
1984 (64)
2016 (32)
2032 (16)
2040 (8)
2044 (4)
2046 (2)
2047 (1)
2047 (0)

Which isn’t what I was looking for, but makes sense since on the last increment it is zero.
Perhaps then, inc isn’t inc it is diff between end and chop point.

So rather than ‘add to’ the start, I should ‘take away’ from the end

    @Test
    public void calculateBinaryChopForStartAndEnd(){

        int start = 1024;
        int end = 2048;
        int choppoint=start;
        int inc = start;

        while(inc > 0){

            inc = (end-choppoint)/2;
            choppoint=end-inc;
            System.out.println(String.format("%d (%d)", choppoint, inc));
        }

    }

Which gives me my original plan:

1536 (512)
1792 (256)
1920 (128)
1984 (64)
2016 (32)
2032 (16)
2040 (8)
2044 (4)
2046 (2)
2047 (1)
2048 (0)

But since I’m working from the end, I’m wondering if what I actually do is just keep halfing the difference:

@Test
public void calculateBinaryChopForStartAndEndHalfDifference(){

  int start = 1024;
  int end = 2048;
  int diff = end-start;

  while(diff > 0){
  diff = diff/2;
  System.out.println(String.format("%d (%d)", end-diff, diff));
  }
}

Which gives me:

1536 (512)
1792 (256)
1920 (128)
1984 (64)
2016 (32)
2032 (16)
2040 (8)
2044 (4)
2046 (2)
2047 (1)
2048 (0)

And is much simpler.

And since this ‘test’ is a useful ‘tool’ for me - I’ll stop there for this video. And next I’ll start refactoring this out into a library for binary chopping so that I can then use that in the Test Tool Hub.


Friday, 21 October 2016

How to create and release a jar to maven central

TLDR; The instructions on apache and sonatype site are pretty good to help get library released to maven central. But you’ll need to learn about pgp signing and might need more rigour in your pom file. A fairly painless learning process that I recommend you go through and release something to the world.




I spend most of my time with Java writing stand alone applications to support testing or code that we run as part of CI. I haven’t had to create a library that I make accessible to other people through maven central.

I thought it was about time I did so.

In this post I’ll describe what I did and how I got a .jar in Maven Central.

What is the Library?

As part of my Selenium WebDriver online training course I created a ‘driver manager’ to allow code to more easily run across different browsers.
It works fine for the context of my course.
Over time I’ve started splitting the course source into multiple parts:
And I’ve had to copy the Driver.java into the continuous integration project.
I decided to pull it out into a separate library and make it accessible via maven central, that way it will be easier for people taking the course to use the Driver class in their own code.
And I can start maintaining it as a project on its own merits with better code and better flexibility, rather than something that just supports the course.

Summary of what to do?

What follows is a ‘checklist’ created from my notes about how I released.
Now that I have a groupid that will synchronise to maven central, it should be a simpler process if I want to create any future libraries.

A bit more detail

The documentation I linked to is pretty good. I mostly just copied the information from there.
And you can see the results in the released library code:
And the sample project that uses the library:

Changed my code to use minimal libraries

One change I made to the library pom.xml that is different from my normal use of the code in projects.
I decided not to include the full version of Selenium WebDriver - which I normally do when I use it:
i.e.
<dependency>
   <groupId>org.seleniumhq.selenium</groupId>
   <artifactId>selenium-server</artifactId>
   <version>3.0.1</version>
</dependency>
Instead I wanted the minimum I could add, since I know that the projects using it will be incorporating the full version of Selenium WebDriver.
So I just used the Java Interface:
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>3.0.1</version>
</dependency>

Configuring repositories in the pom.xml

I haven’t had to do this for a long time. I vaguely remember doing this in the past as a workaround for some local issue we had.
In order to access the -SNAPSHOT release version of the library I have to have the repository configured in my pom.xml
<!-- to use snapshot versionsof the driver manager we need to use the OSS nexus repo -->

<repositories>
    <repository>
        <id>osshr</id>
        <name>OSSHR Staging</name>
        <url>https://oss.sonatype.org/content/repositories/snapshots</url>
    </repository>
</repositories>
I imagine that this might prove a useful workaround if I ever encounter a site that has configured the maven config via settings that we are unable to access easily.

Deploy was easier than I thought

I haven’t used the release deploy in maven before. And the instructions had a whole bunch of commands:
//perform a release deployment to OSSRH with

mvn release:clean release:prepare

//by answering the prompts for versions and tags, followed by

mvn release:perform
But in the end I didn’t have to do this.
I changed the version to remove -SNAPSHOT and it ‘released’ when I did a mvn clean deploy

Tagging a release on Github

I haven’t ‘released’ on Github before so I created a release via the github GUI on the releases page

Gotchas

What went wrong?

I tried to use a groupid that I don’t own

I’ve been pretty laissez-faire with my groupids in my projects and high level package names because I’ve never released one before.
But to use maven central you need to have a domain that you own.
And someone has snapped up the .com that I often use in my code, so I needed to use the .co.uk that I own.
I might well start changing the code that I create to use this new groupid now :)

I put my group id the wrong way round

I tried mvn clean deploy for a snapshot release and I received:
[ERROR] Failed to execute goal org.sonatype.plugins:nexus-staging-maven-plugin:
1.6.7:deploy (injected-nexus-deploy) on project selenium-driver-manager:
Failed to deploy artifacts: Could not transfer artifact co.uk.compendiumdev
:selenium-driver-manager:jar.asc:javadoc:3.0.1-20161020.083347-1 from/to
ossrh (https://oss.sonatype.org/content/repositories/snapshots):
Access denied to: https://oss.sonatype.org/content/repositories/snapshots/co/uk/
compendiumdev/selenium-driver-manager/3.0.1-SNAPSHOT/
selenium-driver-manager-3.0.1-20161020.083347-1-javadoc.jar.asc,
ReasonPhrase: Forbidden. -> [Help 1]
I checked that my credentials were correct by logging into the oss nexus system
My issue was that instead of using groupid
  • uk.co.compendiumdev
I mistakenly used:
  • co.uk.compendiumdev
So don’t do that.

I forgot to release the gpg key

I forgot to release the gpg key when I created it, so I ended up trying to do a final release and seeing the following error during mvn clean deploy
[ERROR]     * No public key: Key with id: (xxxxxxxxxxxxx) was not
able to be located on
&lt;a href=http://pool.sks-keyservers.net:11371/&gt;http://pool.sks-keyservers.net:11371/&lt;/a&gt;.
Upload your public key and try the operation again.
Make sure you do this early in the process.
Also I had to wait 10 - 20 minutes before it was accessible.
To check, visit the site you uploaded to and then search for the key.
I had to search for the key id with 0x in front of it i.e.
  • 0x740585A4
  • and not 740585A4
http://pool.sks-keyservers.net/pks/lookup?search=0x740585A4
When it was available from the search, then I could mvn clean deploy

Future work

I still have a lot to learn here.
As a beginner:
  • I’ve added a lot of ‘stuff’ to the pom.xml that I don’t fully understand and need to research
  • I’m sure I’m taggging the release on Github inefficiently
  • I’ve only done one release so I’m not sure if it is fully setup yet
  • I do this manually and haven’t added a CI deploy - when I do I’ll read the sonatype blog post more carefully
And I have an actual todo list:
  • I need to document the library and example in more detail if I want usage to spread beyond my course.
  • I need to amend my wdci and course code to use the library
But, it was a lot less daunting than I expected and the documentation was pretty clear, and the OSSHR team were very helpful in getting me setup, I was very impressed given that the oss staging repositories and syncing to maven central is a free service.
Hope that helps someone on the road to making their release. All in all it was a good learning experience.

References

Wednesday, 5 October 2016

New Java For Testers Install Videos and Checklist for Windows and Mac Released

TLDR; use the startUsingJavaJunit checklist on github to install Java JDK, and Maven, it also has links to ‘install tutorial’ videos for Windows and Mac



One of the hardest parts of writing a book, is keeping it up to date.

Particularly for install instructions.

Its one of the reasons, that Java For Testers has a checklist approach to the install instructions in the book. And why I have information on the JavaForTesters.com website describing the install.

New Install Instructions

I have just updated the install instructions and videos online because:
  • Maven 3.3.9 has a slightly different install process (no need to create an M2_HOME environment variable, although nothing bad happens if you do, so the old instructions still work)
  • Mac, while ‘easy to use’, forces you to use the command line when installing development tools and people new to programming and command line find this hard - so the install instructions for Mac that I have on the web site, now use Homebrew.
  • IntelliJ GUI has changed enough, since the last time, I created the video that I receive questions on how to import projects
The install instructions are now supported by a Github project:
with an install checklist:
The project is basically a maven project with a single test, so when you run it, you can see that maven, and JDK are working on your machine.
I have install videos for both Windows and Mac:

Tuesday, 27 September 2016

How to fix IntelliJ issues by looking in the IntelliJ log

TLDR; View the IntelliJ log Help -> ‘Show Log in Explorer’


I experienced an issue when importing maven projects.

I found the answer to my problem on StackOverflow:
“…set Settings > Build, Execution, Deployment > Build Tools > Maven > Importing > JDK for Importer to Use JAVA_HOME…”
The above solution worked for me. But it made me realise that it is harder than it needs to be to find what is going wrong with IntelliJ if you don’t know one trick - how to view the logs with IntelliJ.

Monday, 8 August 2016

How to convert a breakpoint into a conditional breakpoint in IntelliJ

TLDR; right click on a breakpoint and add code that returns a boolean to make it a conditional breakpoint

Breakpoints are great. You find the section of code that you want to investigate. Click on the side of the screen to create a breakpoint. Run the code in debug and it stops where you want it.

But what if you only wanted to stop on that breakpoint sometimes.

What do you do?

Add a watch, then when the code stops at the breakpoint, look at the watch and if it is not what you want, carry on?

Well that’s one way.

The other way is a conditional breakpoint.

A breakpoint that only triggers when a certain condition is set.

Let’s have a look.

I have this test.


And it fails!

java.lang.ArrayIndexOutOfBoundsException: 16

    at com.javafortesters.chap009arraysiteration.exercises.
TriangleSquareExercisesDebugTest.createSquare2dArray
(TriangleSquareExercisesDebugTest.java:37)

well, it fails on something when it is 16.

Is it i==16 or is it row==16?

I know. I’ll convert the breakpoint to a conditional breakpoint and find out.

To create a conditional breakpoint I simply right click on the breakpoint symbol and type in a condition.

The condition is any adhoc Java code that will compile in the context of the breakpoint, and return a Boolean.

So I could make the ‘Condition’ i==15 then the breakpoint should only trigger when i equals 15.



Now when the breakpoint fires, I only have to step over once to get to the point where my code throws its error.

Rather than having to step through the loop 15 times.

Worth trying?

Tuesday, 2 August 2016

Is JUnit only for unit testing? What about system testing or UAT?

TLDR; We can use JUnit to execute code to support any type of testing.

Question:

Hi, you use Junit in the book “Java For Testers” and I thought JUnit was used for “unit testing” and “unit testing” was performed by developers , not testers. Is the purpose to learn JUnit and “unit testing” or other types of testing as well? In other words, would you recommend learning “java for Testers” to software testers who would rather not be involved in “unit testing” but rather involved in “system and UAT”?

Q: Is JUnit just for Unit Testing or can we use it for other testing as well? from Alan Richardson on Vimeo.


Answer:

JUnit is used for unit testing. And it is used for other types of testing as well.

I don’t think of JUnit as a Unit Testing Tool. Instead, I view it as a way of running code marked as ‘runnable by JUnit’. That code is marked by @Test annotations and is often called a Test, and those ‘Tests’ are often used for Unit testing, but they don’t have to be.

JUnit can be used as a test runner for any kind of test: e.g. system and integration tests; tests which are interacting with a deployed application.

e.g. the WebDriver tests here all use JUnit github.com/eviltester/webDriverExperiments and they interact with an application which runs in a browser.

And you can see me use JUnit it here to aid my interactive exploratory and system testing of an API:
The name JUnit should not lead you to think that it is only for Unit testing.

If you want to automate, from code, then you’ll need some way of executing the code. In the book we use JUnit as Test Runner to execute code.

I see a lot of examples of “how to learn Java” which use ‘main’ methods to allow execution of the code.

‘main’ methods are a good approach if you want to compile your code into an application.

Unfortunately I’ve seen that when people learn to write Java this way, they often have multiple ‘main’ methods in their code, without really knowing why a ‘main’ method is are used. And they don’t learn any strategies for running bits of code in an adhoc fashion, as well as a strategic fashion.

In the book “Java For Testers” I wanted people to learn Test Driven Development, but not make it a ‘thing’ just a natural process, so all the execution capabilities of the code are provided by @Test annotation, and executed from JUnit. This allows us to:
  • Tactically Run arbitrary code without create main methods or packaging the app
  • Use any library, not just for Unit testing, but also for Testing that integrates with deployed applications e.g. Web or API
  • Strategically create suites which we can use longer term
  • Unit test the abstraction layers and support code that we write so that we do Unit test, our System and Integration test code
  • Easily add our code into a continuous integration approach
Hopefully as you work through the book that will all become clearer.

If you want to automate, you will need to write code, and you’ll want to unit test that code as well, and you’ll use JUnit for that, as well as using JUnit to provide the ability to execute your code.

I rarely unit test the applications I work on as a tester, but I do unit test the code I write to automate those applications as part of my testing.

Hope that makes sense.

P.S. I think you are unlikely to strategically automate as part of a UAT process. But you might tactically automate (adhoc) data setup and configuration, and you’ll need coding skills to do that effectively.

Tuesday, 19 July 2016

How to debug Java with IntelliJ: breakpoints, evaluate expression, watches and variable view

I have deliberately created a failing test. Obviously deliberately since I would never ever create such simple issues in code. I’m far too experienced for that. :)
Even though these issues were created deliberately I still need to know how to debug code. In this blog post I’ll describe how I debug Java using IntelliJ.



You can also 'watch' this post on youtube

 I have some code which fills a dynamic array with “*” to simulate a set of ‘pixels’ - whatever.
But it doesn’t work.
@Test
public void createSquare2dArray(){

    int squareWidth = 16;

    String[][]square = new String [squareWidth][];

    for(int row=0; row<square.length; row++){
        square[row] = new String[squareWidth];
        for(int i=0; i< (squareWidth+1); i++){
            square[row][i] = "*";
        }
    }
   
    print2DStringArrayIterators(square);
    System.out.println("");
}
It throws an error on the line
square[row][i] = "*";
Something about…
   java.lang.ArrayIndexOutOfBoundsException: 16
at com.javafortesters.chap009arraysiteration.exercises.
TriangleExercisesDebugTest.
createSquare2dArray(TriangleExercisesDebugTest.java:40)
It will be fairly obvious to most people what is going on but if I put a breakpoint on the line that is failing then I can Debug the @Test method and step through the code to see what is going on.


Oh look, a breakpoint.



Then run in debug mode.


When the test is running in debug and has stopped at a breakpoint, I can:
  • see all the current variables,
  • expand them when they are an object instance of some sort
  • resume execution (stop at next breakpoint)
  • step over the line to advance execution bit by bit
  • step into the code to advance execution, but into the method implementation
I can also highlight code and “Evaluate Expression”.

This lets me execute code on the fly and experiment with different code constructs.
e.g. I can evaluate square[row][i] note that this is not the full line, just ‘code’.
I can run that and experiment with it
e.g.
  • square[row][i] returns null because we haven’t set the value yet
  • square[row][15] also returns null because we haven’t set the value yet
  • square[row][16] reports java.lang.IndexOutOfBoundsException: Invalid array range: 16 to 16
That IndexOutOfBoundsException seems suspiciously close to the error I saw when I ran the test.
I could add a ‘Watch’ for i even though it is obvious in the Variables list by clicking the green + symbol in the ‘Watch’ section.


So if I step through until i==16 then I can also see in the variables list the exception will be thrown - even though the line hasn’t executed yet.

And we know the problem is that I copied the code from a previous ‘triangle exercise’
String[][]triangle = new String [16][];

for(int row=0; row<triangle.length; row++){
    triangle[row] = new String[row+1];
    for(int i=0; i< (row+1); i++){
        triangle[row][i] = "*";
    }
}
And accidentally left a +1 in the loop condition.
I fix that.
for(int row=0; row<square.length; row++){
    square[row] = new String[squareWidth];
    for(int i=0; i< squareWidth; i++){
        square[row][i] = "*";
    }
}
And then I have a problem in my next method.
Instead of printing out a 16x16 square of *
It prints out:
****************
And here is the horror in all its glory:
public void print2DStringArrayIterators(String [][]multi){

  Iterable<String[]> outerList = Arrays.asList(multi);
  Iterator<String[]> outer = outerList.iterator();

  while(outer.hasNext()){
    String[] innerMulti = outer.next();
    Iterable<String> innerList = Arrays.asList(innerMulti);
    Iterator<String> inner = innerList.iterator();

    while(inner.hasNext()){
       String pixel = inner.next();
       System.out.print(pixel);
    }
    System.out.println("");
    break;
  }
}
I decided to “get fancy” and use iterators and lists instead of just for loops with arrays.
But I didn’t get fancy enough. I should have wrapped my print2DStringArrayIterators with @Test methods and made sure it worked before I used it.

  • Me: “But it prints out, I couldn’t unit test it”
  • Other Me: "You could have written a method that returned the output, and we could have used @Test to assert on its functionality
  • Me: … 
  • Other Me: Yeah, exactly.

But I didn’t do that. So I have to debug it instead.
If I breakpoint the line where the method is called:
print2DStringArrayIterators(square);
Then I can “step into” the method and debug from there.
And As I step through the method, the problem is obvious - the break; that I added by mistake.

Summary

OK. So these were pretty poor examples, but, they are also very similar to code examples that I’ve received emails from, and probably wrote myself back in the day (Monday, or yesterday, or something).
Basics:
  • Yes we prefer to TDD our code
  • if we don’t TDD we better learn how to debug
  • use breakpoints
  • step through code
  • use the ‘variables view’
  • setup up ‘Watches’ if you have a lot of variables
  • use ‘Evaluate Expression’ to experiment in the running code
  • use Resume to run to next breakpoint
  • use Step Into to move to the next level of code in a method
Try it and see.

Thursday, 2 June 2016

Does dependency between test execution imply lack of abstraction layers?

TLDR; I try to write tests at an appropriate semantic level so I never need to create dependencies between @Test methods, I re-use abstraction calls instead of dependencies between @Test methods.

People often email me the question “How do I make a test run after another test?”
I ask “Why do you want to do that?”
“Because I have a test that creates a user, then I want to use that user in another test.”
I generally answer “Don’t do that. Write some abstraction code to ‘create a user’ then use that in your ‘create a user test’ and in your ‘another test’.”
In the examples below I have made up an API for HTTP requests.

API Abstraction vs HTTP Direct with Test Dependencies

So instead of:
@Test
public void canCreateAUser(){

     // Send request to create a user
     Response r =
        myHttpLibrary.post("http://myurl/api/users").
                      withFormContent(
                      new Form().with().
                        field("username","bob").
                        field("password","dobbspass").
                        field("email","bob@mailinator.com").
                        .urlencoded()
                      );
                                   
                         
     Assert.assertEquals(201, r.statusCode);
     
     // URL to access created user is in location header
     // e.g. "http://myurl/api/user/12"
     String userURL = r.getHeader("location");                         

     // get the user and check created properly
     Response u = myHttpLibrary.get(userURL);

     Assert.assertEquals(200, userURL.statusCode);

     Assert.assertEquals("bob",
                         u.parseJson("user.username"));
     Assert.assertEquals("bob@mailinator.com",
                         u.parseJson("user.email"));
}

@Test
public void canAmendAUser(){

     // write the code that amends user
     // created in the test canCreateAUser
}
I would be more likely to write code that looks like the following:

@Test
public void canCreateAUser(){

     Response r = myApi.createUser("bob",
                                   "dobbspass",
                                   "bob@mailinator.com);
    
     Assert.assertEquals(201, r.statusCode);
     
     String userId = ResponseParser.getCreatedUserId(r);

     Response u = myApi.getUser(userId);

     Assert.assertEquals(200, userURL.statusCode);

     Assert.assertEquals("bob",
                         u.parseJson("user.username"));
     Assert.assertEquals("bob@mailinator.com",
                         u.parseJson("user.email"));
}

@Test
public void canAmendAUser(){

     Response r = myApi.createUser("bob",
                                   "dobbspass",
                                   "bob@mailinator.com);
    
     Assert.assertEquals(201, r.statusCode);
     String userId = ResponseParser.getCreatedUserId(r);

     Response a = myApi.amendUser(userId,
                                  "email","newbob@mailinator.com");

     Assert.assertEquals(200, userURL.statusCode);
     
     Response u = myApi.getUser(userId);

     Assert.assertEquals(200, userURL.statusCode);
     Assert.assertEquals("bob@mailinator.com",
                         u.parseJson("user.email"));
}

Again - I’ve made up the API, so it isn’t ‘real’ code, so it might have syntax errors, and it will not work if you try to use it.
But it illustrates the creation of an abstraction layer to access the API which you can re-use, rather than trying to use the @Test method as an abstraction layer.
For me this builds on a quote from Dijkstra from "The Humble Programmer"
“…the purpose of abstracting is not to be vague, but to create a new semantic level in which one can be absolutely precise.”
@Test methods are an attempt to abstract a small set of preconditions, actions and assert on a subset of postconditions to justify the title of the @Test method.
We wouldn’t want to reuse ‘canCreateAUser’ we want to re-use ‘create a user’. We don’t need all the additional assertions in the ‘canCreateAUser’ when we ‘create a User’. We only need those additional assertions when we test the process of creating a user rather than when we create a user for use with other actions.

Why would people avoid creating abstractions?

Since I don’t avoid creating abstractions, I have to ‘suspect’ why people might not code like this. And remember the above is an example of an approach, not an example of ‘great code that you should follow’. There are many ways to implement an abstraction layer around an Api to support re-use and made your @Test code readable and maintainable. This was a first attempt that I thought illustrated the point, and remained readable with only one extra layer of semantics.
Possible reasons:
  • I want to avoid repeating code
  • I don’t want to hide the implementation of calling the API
I’m sure other reasons exist - feel free to comment if you have experience of a good reason, or comment with a link to an alternative experience report.

I want to re-use @Test methods to avoid repeating code

The main code we are trying to avoid repeating is:
     Response r =
        myHttpLibrary.post("http://myurl/api/users").
                      withFormContent(
                      new Form().with().
                        field("username","bob").
                        field("password","dobbspass").
                        field("email","bob@mailinator.com").
                        .urlencoded()
                      );
I don’t think increasing the coupling and dependency between tests worth avoiding the repeated code since I can avoid repeating the code by moving it to an API class. And as a side-effect my @Test method concentrates on the assertion of postconditions rather than the actions.
One other strategy that ‘avoid repeating code’ (while also avoiding abstraction layers) creates is ‘large @Test methods’
Which might mean:
@Test
public void canCreateAmendAndDeleteAUser(){

     // insert lots of direct API
     //        calls and assertions to
     // create a user
     // assert on the users creation
     //        for all post conditions related to create
     // amend the user
     // assert on the users amendment
     //        for all post conditions related to amendment
     // delete the user
     // assert on the users deletion
     //        for all post conditions related to deletion
}
Note, I removed the code because it would be too long, so imagine what the code would be extrapolating from the first example with the myHttpLibrary.
i.e.
  • a single test instead of multiple tests for ‘create’ ‘amendment’ and ‘deletion’
  • if this ‘single’ test fails I don’t know if it was the ‘creation’ or ‘amendment’ or ‘deletion’ by reading test names I have to debug the long test
Instead of an equivalent test using abstractions:
@Test
public void canDeleteAUserAfterAmendment(){

     Response r = myApi.createUser("bob",
                                   "dobbspass",
                                   "bob@mailinator.com);    
     Assert.assertEquals(201, r.statusCode);

     String userId = ResponseParser.getCreatedUserId(r);

     Response a = myApi.amendUser(userId,
                                  "email","newbob@mailinator.com");
     Assert.assertEquals(200, userURL.statusCode);
     
     Response d = myApi.deleteUser(userId);
     Assert.assertEquals(200, userURL.statusCode);

     Response d = myApi.getUser(userId);
     Assert.assertEquals(404, userURL.statusCode);

}
  • In the ‘abstraction’ example, I only assert on the minimum postconditions necessary during the execution i.e. the status codes
  • because I have other tests which check ‘creation’ and assert on more postconditions in the creation and I have other tests which check ‘amendment’ and assert on more postconditions in the amendment, so if there is a problem with ‘creation’ I would expect a ‘creation’ test to fail rather than have to debug a ‘canCreateAmendAndDelete’ @Test
  • I have minimal repeated code because I’m using an abstraction layer
  • I don’t need as many comments because the code is readable

I don’t want to hide the implementation of calling the API

What semantic level is the @Test working at?
Sometimes I have an API abstraction layer which I use for most @Testmethods because I’m not ‘testing’ that specific API call, I’m using it.
  • I might be testing a flow through the system
  • I might be testing the response, not the call
The following code is not at an API semantic level, it is at an HTTP semantic level:
     Response r =
        myHttpLibrary.post("http://myurl/api/users").
                      withFormContent(
                      new Form().with().
                        field("username","bob").
                        field("password","dobbspass").
                        field("email","bob@mailinator.com").
                        .urlencoded()
                      );
Therefore if we are testing the HTTP semantics of the API then this is an appropriate level e.g.:
  • what happens if I add extra headers?
  • what happens if my form fields are in a different order?
  • what happens if it is a PUT instead of a POST
  • etc.

Summary

It never occurs to me to try to make @Test methods dependent on each other.
I generally refactor to abstraction layers very quickly to ensure my @Test methods are written at the semantic level necessary for that @Test.
I combine multiple layers of abstraction to make the semantics in the @Test clear.
I suspect that, if you want to make your @Test methods run in a specific order, or make your @Test methods dependent on other @Test methods, you may not have the correct level of abstraction and are using ‘dependency’ as a mechanism to solve a problem that ‘refactoring to abstraction class’ might solve as quickly, and with more benefit.
Benefits:
  • Don’t worry about dependencies
  • Readable code
  • Easy to maintain when the API changes
  • @Test are not dependent on an HTTP library so you can use different libraries if necessary
  • Re-use the API abstractions for different types of testing - functional, integration, exploratory, performance
  • Fewer issues with parallel execution of @Test code

Thursday, 21 April 2016

Source Code for House Of Test Java Technical Testing Case Study Videos Released

I have released the source code github.com/eviltester/houseOfTestDataGenCaseStudy for my Java Technical Testing Video Case Study
There isn’t too much to the source code. A single @Test method in an Test .java file.
The pom.xml was really just to create a basic project in IntelliJ to use the inbuilt IntelliJ decompiler.
The source code is the code used to ‘test’ the random generation. This won’t work unless you add the data generation tool as a dependent jar as described in the case study videos.
And I haven’t done any work to tidy up the code so again it reflects a ‘write whatever code you need to get the job done’ attitude.
If I use the code more than once then I would revisit it, refactor it, etc. etc.
But I didn’t. I used it during the case study and now it lives on github.
You can find more details about the case study in this blog post

Thursday, 14 April 2016

An example of creating a 'tool' using @Test methods without building a Java application

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. I do explain main methods over here.
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 @Testmethods 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

Tuesday, 22 March 2016

What is a Java `main` method - simple example

One of the topics I don’t cover in "Java For Testers" is the main method. I explain why my coding style ‘as a tester’ doesn’t really require main methods in this blog post.
And in this blog post I’m going to start to explain the main method.
Why?
To round off our Java education a little so that if you do want to start writing small applications or package your well written Java library code into an app, then you know how to go about doing it.


Create a Project

My basic steps, and I’m not going to cover them in detail because they are covered in Java For Testers:
  • creating a maven project in intellij,
  • but I’m not going to add any dependencies into the pom file.

Create a class with main method

And I will create the standard “Hello World” application:
  • create a class
  • create a public static void method called main which takes a String array as arguments
  • for the body of the method I will println the String "Hello World!" to the standard out
package com.javafortesters.main;

public class HelloWorldOutputter {

    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}
Because we have written a lot of @Test methods in the IDE, we know that we can right click on a method and run it as a JUnit Test.
We can do the same to the main method we have just written and right click it to run it.
And we should see "Hello World!"printed to the console.
Great, so we’ve written our first app then?
Actually, no. We have written a class with a main method.

Create a .jar file

We have to first of all create a .jar file.
Since we used Maven we can do that very simply from the command line by typing mvn package
And then in our target folder we will see the ‘application’ as a .jar file.
Woo hoo. So now we have written our first app?
Actually no. Try running it
D:\>java -jar mainMethodInvestigation-1.0-SNAPSHOT.jar

no main manifest attribute, in mainMethodInvestigation-1.0-SNAPSHOT.jar

I need a manifest attribute?

Yes.
But we could run it now without a manifest attribute.
Java allows us to run any main class in the classpath from the command line, it just makes things a little more complicated for the average user. You can see examples of me doing this in my "Technical Testing Case Study"
The manifest attribute makes it easier.
D:\>java -cp mainMethodInvestigation-1.0-SNAPSHOT.jar com.javafortesters.main.HelloWorldOutputter
Hello World!
What we’ve basically said here is. Java, add mainMethodInvestigation-1.0-SNAPSHOT.jar to the classpatth and run the main method that you find in class com.javafortesters.main.HelloWorldOutputter and yes, you need the full package.
Woo hoo?

But I really want a manifest attribute

OK, that is easy to add into maven.
At its most basic, and for this current ‘application’ it can be pretty basic. We just need to use the maven-jar-plugin and configure the mainClass. documentation
To do that, we add the following into the pom.xml
<build>
    <plugins>
        <plugin>
            <!-- Build an executable JAR -->
            <!-- http://maven.apache.org/shared/maven-archiver/index.html#class_manifest -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>com.javafortesters.main.HelloWorldOutputter</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>
And now, when I run mvn package.
And then when I run the .jar
D:\>java -jar mainMethodInvestigation-1.0-SNAPSHOT.jar
Hello World!
So is that an application?
Yes it is.
Woo hoo!
There is some information on the Oracle site:

Tuesday, 8 March 2016

Use of Java for Technical Testing Case Study


When we learn Java, or think about learning Java, we may have a limited model of the possibilities that the knowledge opens up for us.

As we learn we develop skills we may be unaware of:


  • Use of IDE
  • General Debugging Skills
  • Breakpoint running code
  • Inspect variables when debugging
  • Running Java applications from the command line
  • Ability to review Java Code
  • Understanding exception messages
All of this can help us with our Technical Testing.

I have created a set of case study videos, about an hour long, showing these skills in action, while technical testing of a couple of Java desktop applications.

If you haven't read Java For Testers yet, then this video series will give you an idea of the way that Testers can apply they Java knowledge they learn.

And if you have read Java For Testers, then this might reveal opportunities to expand your testing that you haven't explored yet.

The case study videos are free, you just have to sign up to the video course to watch it.