Monday, 26 August 2013

Do you adhere to the Single-Responsibility Principle?

The single-responsibility principle is one of the fundamental principles of object orientated design.  It is the idea that any object, method, variable etc has one purpose and one purpose only.

'Yes', I hear you say, 'I'm a super-duper expert in object-orientated design. I follow this principle and I defy you to find a single part of my code where I haven't followed SRP!'

Well, dear reader, how are your tests?

In my opinion, the SRP should apply to tests as well, meaning that every test should have a point, and one point only. Here is a little example showing a common way to structure tests:

Here is a little MessageListener.java class.  When the a message is received, the onMessage method is called and the messageListener both stores the message and increments a counter of the total number of messages received.


All is beautiful so far.

However here is our MessageListenerTest.java:


What on earth is going on here? This test is not adhering to the SRP as it is clearly testing multiple things.  There are 6 asserts in one test, which should set off alarm bells.  If the messageCount is broken in the message listener, or the message isn't added to the receivedMessages collection etc, then this test will fail and the developer will have to waste time figuring out exactly what went on.  Okay, in this example it's not exactly difficult to understand what is happening, but in more complicated examples this problem quickly becomes apparent.

How about writing the test like this:

Every test method has one distinct purpose which is summed up in the method name.  If a test fails, you can immediately understand what has failed and which part of the code is incorrect.


So, things to look out for in your own code:

- a test method with some code, then asserts, then more code, then more asserts.
- if you break one tiny bit of your application, how many tests fail? If we change one tiny bit and suddenly 20 tests break all over the shop then what is going on? 

Sunday, 25 August 2013

Simple JUnit Example Test

This is a simple introduction to using JUnit to unit test classes.

I am writing this post because recently a friend of mine started to dabble in Java and in order to test his code he was fiddling around with a main method and printing expected output etc.  Manual tests like this can seem quick initially, but you can't check everything every time you make a change. Investing half an hour in setting up some tests will save you oodles of time later.

Put JUnit on your classpath

You can manually add it by downloading it from the junit site and in your eclipse project do the following: 

Right click on JRE System Library > Build Path > Configure Build Path > Libraries > Add External Jar. 

Navigate to wherever you have stored the junit jar locally and click okay: it should now be on your classpath (and you should see junit.jar or something similar under 'JRE System Library').

Alternatively you can use a nice dependency management tool like Maven or Ivy.  With Maven you don't even need to do anything - JUnit jars are on the classpath by default when you create a maven project. 

Sample class to Test

 I have a very simple 'Circle.java' class with 1 method to test: 



Using JUnit to write tests

Test methods have the annotation '@Test' above them.  The '@Before' annotation means that that method (in this case the method called 'setup') is called before every class. 

Note that all test methods (ie methods with the @Test annotation must be public, void, and take in no parameters). 


To run this test from eclipse - 
Right click anywhere in the class > Run As > JUnit Test

Boom, done. 







Folder Structure of a Java Project

My favourite way of structuring a Java project is into the following folders (in eclipse: File > New Folder. For the two folders calls 'Java' you should also right click on the folder after it has been created, go to 'Build Path' and choose 'Use as source folder'):

-- src
        -- main
                -- java
                -- resources
        -- test
                -- java
                -- resources

This is basically the maven way of organising projects (if you haven't heard of maven then don't worry about that right now).

What goes where? 

  • src/main/java
    • This is where your Java code will live.  It will be nicely arranged into packages (which I will discuss shortly)
  • src/main/resources
    • As you many have guessed, this is where any files other than .java files can go.  For example, if you are using properties files to configure parameters in your application, you might have a file 'src/main/resources/properties/my-awesome-properties-file.properties'.  
  • src/test/java
    • This is where your tests will go. I usually have the structure of this folder mirroring the structure of src/main/java. For example if you have a class 'Circle.java' in the package 'com.ojha.shapes' in src/main/java, then I would have a corresponding package 'com.ojha.shapes' in src/test/java with a class 'CircleTest.java'. 
  • src/test/resources
    • If, for example, you are writing tests to check you can read in a file correctly or something then you might put sample files for your tests in this folder. Another very popular use case is if you are using Spring and want to separate your test configuration from your application configuration. 
Why should I do this?

- You test code should have nothing to do with your application code and you are reflecting this separation by physically putting the code and resources in separate location. 

- Your tests can mirror the package and class structure of the main code which makes it easier to structure tests logically.

- It is a commonly used pattern in Java projects.  Being a Software Engineer isn't just about making code work but also producing clean, logical, intuitively-understood code bases.


Note that if you create folders and organise your files within eclipse, the same folder structure is reflected in the filesystem. This is not the case in Visual Studio where you can arrange your classes nicely into folders within your IDE, but then they end up in different places on disk (this confused me a lot when I first moved to C#!) 





Scala with Cats: Answers to revision questions

I'm studying the 'Scala with Cats' book. I want the information to stick so I am applying a technique from 'Ultralearning...