For testing business logic in my back end applications I mostly used ColumnFixture, TableFixture and RowFixture for defining inputs and output data sets. All I needed to write was a thin adapter or mapper Java class that extends any of these fixtures. That thin adapter Java class just gets input data from wiki and use that data to make a call to my back end application. At the end of the call it just makes the result available for FitNesse to display on wiki page. This thin adapter class is fully Fixture aware and developer of this class must know how to map data between back end application and FitNesse front end wiki page.
So far so good no major complains here, it worked great for us.
But I found this requirement to write the thin fixture adapter class for each new transaction a little annoying and have always toyed with the idea of building a generic Table/Fixture, one that will not require a developer to understand and be aware of the various fixtures coding conventions. In other words a fixture/table style where testers can write acceptance tests without needing development support of writing fixture specific code for each new transaction.
That became the main driving force behind the thought of developing a Generic Fixture where you just drop your class in FitNesse’s class path, write your test tables in wiki and be ready to test without having to write a single line of Java code. This idea is simple enough to understand but not so simple to implement because of the complexity of Java classes. Each class is different, it can have various type of constructors and methods (even overloaded ones). Each method can be returning different type of values (or not returning at all if method is void). We have to define some rules of defining class names, constructors, method names and their return types on wiki test tables first.
So here they are:
- Name of the class to test or system under test (SUT) and arguments to the SUT’s constructor must come in a separate cell of the very first row of the table. (Starting from 2nd cell, since 1st cell is reserved for name of the Fixture Class itself). eg:
!| Generic Fixture | java.lang.String | It’s a cool fixture | - Each row of the table will have a method name in the 1st cell followed by method parameters appearing each in a separate cell.
- Leave an empty cell after end of parameters and start of return values. eg:
| indexOf | cool | | 7 | | concat | !! | | It’s a cool fixture!! | - Class that is being tested can have methods accepting parameters of all primitive types (int, float, double etc) as well as of all the primitive Java wrapper classes (Integer, Double, String, Number Date etc).
- If methods need to accept user defined object in parameters then those user defined types must provide a method: public static Object parse(String str) { … }. An example of this is provided below in the Address class.
- Methods with return types of all primitive types (int, float, double etc) as well as of all the primitive Java wrapper classes (Integer, Double, String, Number etc) should be supported.
- Methods can also return array of all primitive types (int, float, double etc) as well as of all the primitive Java wrapper classes (Integer, Double, String, Number etc).
- Class that is being tested can be a non-instantiating class like java.lang.Math. In this case all methods will be invoked statically.
- Calls to static method must be allowed in the form of CanonicalClassName.MethodName eg:
| java.lang.Thread.sleep | 1000 | - Should be able to operate with overloaded methods in a class. For example abs() method in java.lang.Math class:
| abs | -5.72 | | 5.72 | - It should be able to store return value of a method into variables and a variable can be of any type. And later on this variable can be used anywhere in the test to pass a value, compare a return value, creating a new class or becoming a target itself. Please visit my other post Use of variables, arrays and complex types in Generic Fixture for more details.
Putting it all together: Lets write a simple test table for testing java.lang.String class. Lets say we have a Java code like this:
java.lang.String aString = new java.lang.String ( "It's a cool fixture" );
assertEquals ( aString.indexOf ( "cool"), 7 );
assertEquals ( aString.concat ( ", indeed" ), "It’s a cool fixture, indeed" );
assertEquals ( aString.compareTo ( "It’s a cool fixture" ), 0 );
assertEquals ( aString.equalsIgnoreCase ( "" ), false );
assertEquals ( aString.concat ( "" ), "It’s a cool fixture" );
assertEquals ( aString.equals ( "" ), false );
assertEquals ( aString.matches ( "^.*cool fix.*$" ), true );
System.out.println ( aString.toCharArray () );And here is the FitNesse equivalent of above Java code using Generic Fixture:
!| Generic Fixture | java.lang.String | It's a cool fixture |
| indexOf | cool | | 7 |
| concat | , indeed | | It's a cool fixture, indeed |
| compareTo | It's a cool fixture | | 0 |
| equalsIgnoreCase | blank | | false |
| concat | blank | | It's a cool fixture |
| equals | blank | | false |
| matches | ^.*cool fix.*$ | | true |
| toCharArray | |
Click on Test button and you will get these results:
Assertions: 7 right, 0 wrong, 0 ignored, 0 exceptions
In this test we tested java.lang.String class and some of its methods. Notice last call in the test table above is String.toCharArray(), here we are not validating output of this call just getting output displayed. Nice thing is that we did not write any Java code for the String class we tested above. Looks pretty simple, isn’t it?
Let’s write another test table for java.lang.Math class where all the methods are declared as static:
!| Generic Fixture | java.lang.Math |
| sqrt | 25 | | 5.0 |
| round | 2.51 | | 3 |
| max | 3.469 | 3.47 | | 3.47 |
| java.lang.Thread.sleep | 1000 |
| abs | -5.72 | | 5.72 |
Click on Test button and you will get:
Assertions: 4 right, 0 wrong, 0 ignored, 0 exceptions
Again this Generic fixture was able to do the magic behind the scene and run all the static methods of java.lang.Math class. Did you notice I am calling | java.lang.Thread.sleep | 1000 | for introducing a delay of 1000 ms (1 sec) between max and abs method calls. This is the equivalent Java code for above fixture:
assertEquals ( Math.sqrt ( 25 ), 5.0 );
assertEquals ( Math.round ( 2.51 ), 3 );
assertEquals ( Math.max ( 3.469, 3.47 ), 3.47 );
java.lang.Thread.sleep ( 1000 );
assertEquals ( Math.abs ( -5.72 ), 5.72 );So far we tested 2 Java classes without writing any code. You must be thinking why are we wasting our time testing standard core Java classes that everybody knows are working fine. How to write a meaningful acceptance test for a class of our own? So let’s take an example of a trivial Address class. Code is included here for reference:
Source Code Address.java
public class Address {
public static class Name {
private String surname = null;
private String firstname = null;
public Name() {
}
public Name(Name n) {
this.surname = n.surname;
this.firstname = n.firstname;
}
public static Object parse(String s) {
Name n = new Name();
String[] arr = s.split(" ");
if (arr.length == 2) {
n.setFirstname(arr[0]);
n.setSurname(arr[1]);
}
return n;
}
@Override
public String toString() {
return this.firstname + " " + this.surname;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
}
private int streetNo = 0;
private String street = null;
private String city = null;
private int postcode = 0;
private String state = null;
private Name name = null;
public Address() {
super();
}
public Address(Integer streetNo, String street, String city, int postcode,
String state) {
super();
setAddress(streetNo, street, city, postcode, state);
}
public void setAddress(Integer streetNo, String street, String city,
int postcode, String state) {
this.streetNo = streetNo.intValue();
this.street = street;
this.city = city;
this.postcode = postcode;
this.state = state;
}
public void setStreetNo(Integer streetNo) {
this.streetNo = streetNo;
}
public Integer getStreetNo() {
return this.streetNo;
}
public String getStreet() {
return this.street;
}
public void setCity(String city) {
this.city = city;
}
public String getCity() {
return this.city;
}
public void setPostcode(int postcode) {
this.postcode = postcode;
}
public int getPostcode() {
return this.postcode;
}
public String getFullAddress() {
return this.streetNo + " " + this.street + ", " + this.city + ", "
+ this.state + " - " + this.postcode;
}
public void setStreet(String street) {
this.street = street;
}
public String getState() {
return this.state;
}
public void setState(String state) {
this.state = state;
}
public Name getName() {
return this.name;
}
public void setName(Name name) {
this.name = name;
}
}
Let’s assume I compiled this Address class and added it in FitNesse classpath. Now let’s go about writing an acceptance test table for this Address class using Generic Fixture.
!| Generic Fixture | Address | 123 | Nutley Street | New York | 21019 | NY |
| getStreetNo | | 123 |
| getCity | | New York |
| getState | | NY |
| getFullAddress | | 123 Nutley Street, New York, NY - 21019 |
| setStreetNo | 111 |
| setPostcode | 20133 |
| getPostcode | | 20133 |
| getStreetNo | | 111 |
| getState | | NY |
| setName | John Smith |
| getName | | John Smith |
Click on Test button and you will get:
Assertions: 8 right, 0 wrong, 0 ignored, 0 exceptions
Pay special attention to setName method in above test table. This method is taking a user defined object of Name type. Since I have implemented public static Object parse(String str) method in above code, generic Fixture is able to construct a Name object from the entered string “John Smith” in the table cell.
For the reference purpose above fixture is executing this Java code using Java reflection APIs:
Address addr = new Address(123, "Nutley Street", "New York", 21019, "NY" );
assertEquals ( addr.getStreetNo(), 123 );
assertEquals ( addr.getCity(), "New York" );
assertEquals ( addr.getState(), "NY" );
assertEquals ( addr.getFullAddress(), "123 Nutley Street, New York, NY - 21019" );
addr.setStreetNo ( 111 );
addr.setPostcode ( 20133 );
assertEquals ( addr.getPostcode (), 20133 );
assertEquals ( addr.getStreetNo(), 111 );
assertEquals ( addr.getState(), "NY" );
addr.setName ( "John Smith" );
assertEquals ( addr.getName(), "John Smith" );That’s it, writing acceptance tests could be as simple as that. One more good thing about this Generic Fixture is that it eliminates the need of writing a separate Unit test class (eg: JUnit) for testing your business class.
Generic Fixture download and install instructions can be found on this page. And here is the complete source code for Generic Fixture for browsing. Please leave your comments, suggestions, bug reports, area of improvements and criticism for this effort.
Next Part: Use of variables, arrays and complex types in Generic Fixture
Coming up: Writing web application tests using this Generic Fixture In the next post I will demonstrate use of this Generic Fixture in writing some useful acceptance tests for Web applications.
Visit FitNesse Group Forum for a meaningful and thought provoking discussion on Generic Fixture.
Hi Anubhava,
Thanks for the great plugin. I’ve got it running in FitNesse.
Would you know if it can be made to work with the GUI Runner?
Brgrds.,
Sanne
[...] What we are going to write essentially is translation of Java based JMS client into FitNesse using Generic Fixture, which can be used to write acceptance tests to validate almost any type of Java [...]
[...] visit http://anubhava.wordpress.com/2008/02/09/introducing-generic-fixture-for-fitnesse/ Possibly related posts: (automatically generated)Testing EJBs using Generic [...]
Hi Anubhava,
The Generic Fixture seems good and useful. I tried out few examples and it works fine. Now coming to my projec, I have downloaded the genericfixture,java file and placed in C:\fitnesse. Then in the fitnesse class path table I placed the !path genericfixture.path. Then I tired following to store the return value from my test method:
!1 Create Kml:share with default attributes and click on share button
!|Kap.fixture.KmlShareFixture|
|TestManagerID|172872|Browser|${Browser}|
|KahaAccountID|${UserName}|KahaAccountPasword|${Password}|
|KapServer|${KapServerURL}|KapApplicationName|${App}|
|getEmailCount|//p[@id='Kap-sharedialog-count']|
the last method call actually return a int. I want to store it in a variable, like this:
|iniCount = getEmailCount|//p[@id='Kap-sharedialog-count']|
and use iniCount later in the same test case for comparison.
But whenever I run the test, I get the exception that the method iniCount=getEmailCount not availble. If I put your sample test in the same table and run, it works fine.
Am I missing something? Need your help to use generic fixture successfully.
Hi Sudhindra,
Please don’t use GenericFixture.java available on this blog, it is really a very initial version of GenericFixture. Please download the latest genericfixture.jar file from the sourceforge using this link: http://sourceforge.net/project/showfiles.php?group_id=217699&package_id=262459&release_id=577936 or visit http://genericfixture.sourceforge.net/ and click on download link on the left to download genericfixture.jar
genericfixture.jar has compiled classes and most recent java files as well.
Thanks,
Anubhava
Hi Anubhava,
I tried with the latest genericfixture.jar, I am getting this error:
Missing method: public TypeOfResult myVarEqualsExpectThisElement(Type1 arg1) { } in class Kap.fixture.KmlShareFixture
Also whats the importance/function of the below line :
!| Generic Fixture | Address | 123 | Nutley Street | New York | 21019 | NY |
similar line needs to be there in my test case also?
Hi Sudhindra,
This line:
!| Generic Fixture | Address | 123 | Nutley Street | New York | 21019 | NY |
is actually constructing a new object (creating an instance) of class Address with the parameters 123, Nutley Street, New York, 21019, NY
e.g. it is Genericfixture translations of this java code:
new Address ( 123, “Nutley Street”, “New York”, 21019, “NY” );
Regarding the error you are getting if you copy/paste the test script you are using I can try to find the problem.
Thanks,
Anubhava
Hey Anubhava,
Can return type of my method be an object for ur generic fixture…If not is their any other fixture where it is possible
Regards,
Nimesh
Hi Nimesh,
Return Type of your method can be ANY object (even the user defined objects). GenericFixture supports any type of return objects. For example on returning user defined type please see my post: http://anubhava.wordpress.com/2008/04/11/use-of-variables-arrays-and-complex-types-in-generic-fixture/
In the above post I have an example of Address class where I am returning object Name and storing it into variable called name
Please let me know if you have any further questions or doubts.
Thanks,
Anubhava
Hey,
Thanx for replying bfr……
One more thing how to get the logs of the functions called during compilation…..i cant find them does fitnesse disable this function
Regards,
Nimesh
Hi Nimesh,
If your functions/methods are writing logs on stdout then you can see that output by clicking on “yellow color triangle” available on top-right corner of your FitNesse results page (page that comes after clicking test).
Additionally you can generate debug level info from GenericFixture itself if you add following test script on top of your FitNesse test page.
!| Generic Fixture | Generic Fixture |
| set debug | true |
This information will also be available on STDOUT and you can see that by clicking on “yellow color triangle” available on top-right corner of your FitNesse results page.
Thanks,
Anubhava
Hi Anubhava,
How can I use assertConfirmation in generic fixture?
Thanks and regards,
Vimala
Dear Vimala,
There are various ways to use assert/confirmation in Generic Fixture.
1. In my example above (see !| Generic Fixture | java.lang.String | It’s a cool fixture |) I have shows how to translate assert calls of JUnit into Generic Fixture. Basically you give return expected value in the same row and your cell will turn red or green.
2. If you want to do complex assertion (such as regular expression matching or mathematical comparison) then store return value of method in a variable and use java.lang.String or java.lang.BigDecimal class to do such expressions. Please see my other post on using variables: http://anubhava.wordpress.com/2008/04/11/use-of-variables-arrays-and-complex-types-in-generic-fixture/
Thanks,
Anubhava