Minggu, 24 Agustus 2014

JUnit Testing Tips - Constructor is Called Before Executing Test Methods



Most of Java programmers either use JUnit or TestNG for there unit testing need, along with some mock object generation libraries e.g. Mockito, but not everyone spend time and effort to learn subtle details of these testing libraries, at least not in proportion of any popular framework e.g. Spring or Hibernate. In this blog post, I am sharing one of such details, which has puzzled me couple of years ago. At that time, though I had been using JUnit for significant time, I wasn't aware that code written inside constructor of Test class is executed before each test method.  This behaviour of JUnit has caused, some of my test to failed and putting hours of investigation in my code, without realizing that this is happening because of JUnit is initializing object by calling constructor before executing test method annotated with @Test annotation. I had following code to test my vending machine implementation as coding exercise. If you look at closely, I have initialized vending machine in class body, which is executed as part of constructor. I was assuming one instance of vending machine is shared between all test methods, as I was not using @Before and @After, JUnit 4 annotation for setup() and tearDown(). In first test, one item from Inventory is consumed and in second test another item, but when you assert count of items based upon previous test, it will fail, because you are testing a different vending machine instance, which has different inventory.  So always, remember that JUnit calls constructor of test class before executing test method. You can verify it by putting a System.out.println message in constructor itself.








Code Written in Constructor is Executed before each Test Method




JUnit Tips for Java ProgrammersHere is code example of a JUnit test, which will demonstrate this point.  In our JUnit test class VendingMachineTest we have two test methods, buyDrinkWithExactAmount()  and  buyDrinkWithExactAmount(), and we are printing message from constructor. In the output section, you can see that message from constructor has appeared two times, one for each test case. This proves that constructor of JUnit test class is executed before each test method.







import java.util.List;


import org.junit.Test;


import static org.junit.Assert.;





/**


 
*


 
* @author Javin


 
*/


public class VendingMachineTest {


   
private VendingMachine machine = new
VendingMachine();


  


   
public VendingMachineTest(){


       
System.
out.println("JUnit Framework calls
Constructor of test class before executing test methods"
);


   
}





   
@Test


   
public void buyDrinkWithExactAmount(){


       
int price = machine.choose(Item.COKE);


       
assertEquals(
70, price);


       
assertEquals(Item.
COKE, machine.currentItem);


      


       
machine.
insert(Coin.QUARTER);


       
machine.
insert(Coin.QUARTER);


       
machine.
insert(Coin.DIME);


       
machine.
insert(Coin.DIME);


       
assertEquals(
70, machine.balance);


       
assertEquals(
7, (int) machine.coinInvertory.getCount(Coin.DIME));


       
assertEquals(
7, (int) machine.coinInvertory.getCount(Coin.QUARTER));


      


       
Item i = machine.
dispense();


       
assertEquals(Item.
COKE, i);


       
assertEquals(
4, (int) machine.itemInvertory.getCount(i));


      


       
List change = machine.
getChange();


       
assertTrue(change.
isEmpty());


      


      


   
}


  


   
@Test


   
public void buyDrinkWithMoreAmount(){


       
int price = machine.choose(Item.SPRITE);


     
  assertEquals(
90, price);


       
assertEquals(Item.
SPRITE, machine.currentItem);


      


       
machine.
insert(Coin.QUARTER);


       
machine.
insert(Coin.QUARTER);


       
machine.
insert(Coin.QUARTER);


       
machine.
insert(Coin.QUARTER);


      


    
   assertEquals(
100, machine.balance);


       
assertEquals(
9, (int) machine.coinInvertory.getCount(Coin.QUARTER));


      


       
Item i = machine.
dispense();


       
assertEquals(Item.
SPRITE, i);


       
assertEquals(
4, machine.itemInvertory.getCount(i));





        //this was
failing, because by default VM initialize inventory with 5 items


       
assertEquals(
4, machine.itemInvertory.getCount(Item.COKE));





      


       
List change = machine.
getChange();


       
assertEquals(
1, change.size());


       
assertEquals(Coin.
DIME, change.get(0));


       
assertEquals(
4, machine.coinInvertory.getCount(Coin.DIME));


             


   
}





Output:


Testsuite: test.VendingMachineTest


JUnit Framework calls Constructor of
test
class before executing test methods


JUnit Framework calls Constructor of
test
class before executing test methods


Tests run: 2, Failures: 1, Errors: 0, Time elapsed: 1.421 sec





Result


------------- ----------------
---------------


Testcase:
buyDrinkWithMoreAmount(test.
VendingMachineTest):      FAILED


expected:<4> but was:<5>


junit.framework.AssertionFailedError: expected:<4> but was:<5>


       
at test.
VendingMachineTest.buyDrinkWithMoreAmount(VendingMachineTest.java:63)




That's all guys. I feel this is a worth knowing detail if you are using JUnit for writing unit test in your Java project. Sometime, we have bug in unit test itself, but we suspect our code. So it must for all Java developers to know nitty gritty of JUnit testing framework as well



























Source:http://javarevisited.blogspot.com/2013/12/junit-testing-tips-constructor-is.html

Tidak ada komentar:

Posting Komentar