|
JUnitQuickTutorial
A quick JUnit tutorial for beginners
JUnit 4.x Quick Tutorialby Wishnu Prasetya This tutorial is for novice Java programmers who try to learn JUnit. How does JUnit work?JUnit is a library packed in a jar file. Among other things it contains a tool (called test runner) to run your test files. It is not an automated testing tool: you still have to write your test files by hand. JUnit does give you some support so that you can write those test files more conveniently. Suppose you have a class C that you want to test. We will write the tests in a new class; let’s call it Ctest. This Ctest is our test file. Actually, test class is a better name. We will typically group the tests in Ctest in a bunch of methods called test methods. You will see an example soon. To actually test C we need to execute its test class Ctest. This is done by calling JUnit’s test runner tool; we pass the name Ctest to it. That’s all. JUnit will then execute Ctest for you. JUnit will report how many of the test methods in Ctest succeed, and how many fail. The detail of each failure will be reported; this will be in the form of a print of Java’s stack trace leading to the location of the failure. Locate it firstIf you don’t have JUnit yet, you need to download it (from JUnit site). To use it you just need the jar file. A full download also contains its documentation. Now locate where this jar file is; it is usually called: junit-<version-number>.jar To use JUnit you will need to add the full path to this jar to your class path. We will see examples latter. A simple exampleLet us consider the simple class below. This is the class that we want to test; but first let me explain a bit about what it is. The class is called Subscription; an instance of it represents a subscription to something (e.g. newspaper, but it doesn’t really matter here). Each subscription has its total price, stored in the variable price. This price is in Euro-cent. It also has the length of the subscription, given in months. public class Subscription {
private int price ; // subscription total price in euro-cent
private int length ; // length of subscription in months
// constructor :
public Subscription(int p, int n) {
price = p ;
length = n ;
}
/**
* Calculate the monthly subscription price in euro,
* rounded up to the nearest cent.
*/
public double pricePerMonth() {
double r = (double) price / (double) length ;
return r ;
}
/**
* Call this to cancel/nulify this subscription.
*/
public void cancel() { length = 0 ; }
}For example, new Subscription(1000,2) will create a new subscription of 1000 Euro-cent for the total period of 2 months. By the way, the class has a number of bugs; e.g. pricePerMonth is supposed to return the price per month in euro. However it calculates the price in cent. Let’s write a testLet us write two simple tests to check if pricePerMonth correctly calculates the price per month:
Of course we can write tests without JUnit; but this tutorial is about JUnit. So here is how we write them in JUnit. Each of the tests above will be implemented as a test method; you then group your test methods in a test class. Usually you would group all the test methods that test a certain target class C is a test class called CTest, but you can also have multiple test classes if you want, and call them whatever you want. Here is my test class implementing the above two tests: import org.junit.* ;
import static org.junit.Assert.* ;
public class SubscriptionTest {
@Test
public void test_returnEuro() {
System.out.println("Test if pricePerMonth returns Euro...") ;
Subscription S = new Subscription(200,2) ;
assertTrue(S.pricePerMonth() == 1.0) ;
}
@Test
public void test_roundUp() {
System.out.println("Test if pricePerMonth rounds up correctly...") ;
Subscription S = new Subscription(200,3) ;
assertTrue(S.pricePerMonth() == 0.67) ;
}
}The marker @Test is called an annotation in Java. When we later execute JUnit’s test runner it needs to know which methods in your test class are test methods (e.g. you may have several helper methods in your test class). The @Test is used to mark that a method is a test method. In the first test (test_returnEuro) we first create a Subscription; we call it S. Then we want to check that S.pricePerMonth() will return the expected value of 1.0. The checking is done by the code: assertTrue(S.pricePerMonth() == 1.0) By the way, the annotation @Test and the method assertTrue are things exported by the JUnit library; so you need the imports as in the above code to use them. Compiling and executing your testNext we want to execute the above test class (SubscriptionTest). I’ll show how to do this from a console. If you use an IDE the steps are a bit different. Open a console. You first need to compile the test class, and then you can execute it. The commands are (in Windows): prompt> javac -cp .;<full path to JUnit.jar> SubscriptionTest.java prompt> java -cp .;<full path to JUnit.jar> org.junit.runner.JUnitCore SubscriptionTest (In e.g. Mac you probably have to use ':' instead of ';') The first command will compile the test class. The second will execute JUnit’s test runner; we pass to it the name of your test class. This is what you will get from JUnit; it reports that both tests fail. Notice also that it reports which lines exactly in your test class fail. Time: 0,015
There were 2 failures:
1) test_returnsEuro(SubscriptionTest)
java.lang.AssertionError:
...
at SubscriptionTest.test_returns_Euro(SubscriptionTest.java:13)
...
2) test_roundUp(SubscriptionTest)
...
at SubscriptionTest.test_roundUp(SubscriptionTest.java:19)
...
Tests run: 2, Failures: 2The next thing you want to do is to fix your Subscription class and then test it again. We keep fixing it until we get no more failures. You may in the mean time also want to add more tests to your test class. What now!?That’s it! Now go and write your own tests. Further reading
END. |
Why do you prefix your test methods with "test"? What if you used something more expressive?
To benrady:
No reason really, other than it's an old habbit :) I suppose you can name it anything you want as long as it is still within Java's naming convention. So, it can be:
@Test public void test_if_pricePerMonth_returns_Euro() { ... }which is much more informative. Is this what you mean by "more expressive"?
There seems to be a problem with the test_if_pricePerMonth_returns_Euro() method. Shouldn't it be asserting if S.pricePerMonth() is 1.0 since 200 cents for 2 months comes out to 100 cents per month which is 1.0 euro.
You're right! Thanks!
dude, this is great!!!
java, it seems to me suffers from an inherent lack of decent help - windows has its charles petzold, python has its mark pilgrim ...
thanks
Java names like test_if_pricePerMonth_returns_Euro() gives me Corba nightmares.
Discover Java naming conventions before publishing next time.
Oh ok ... I'll revert it back to simple name, since it is a tutorial for starters.
For advanced testers, I don't completely agree with you. In a real situation I expect you to have lots of test methods. Java name can be arbitrary long, so that you can embed useful information in it, which you can recover via reflection. This can be useful for e.g. making global reports on your set of test methods.
He is not referring to the length of your method names. He is talking about Java conventions for the style of names, i.e:
TestIfPricePerMonthReturnsEuro?()
versus
test_if_pricePerMonth_returns_Euro()
Oooh ... Ok. In that case I find the first rather ugly. At least my poor eyes will have to work twice as hard to auto-insert the spaces.
I think your underscores are fine when describing an action. It gives it a little scheme feel which is comfortable.
Beautiful and straight-forward. Thanks! Passes for
public double pricePerMonth()
Sweet!
hi, i tried to run this example but i had a problem. When i tried to compile the test i took response: javac -cp /usr/share/java/junit4-4.3.1.jar SubscriptionTest?.java
SubscriptionTest?.java:12: cannot find symbol symbol : class Subscription location: class SubscriptionTest?
SubscriptionTest?.java:12: cannot find symbol symbol : class Subscription location: class SubscriptionTest? SubscriptionTest?.java:19: cannot find symbol symbol : class Subscription location: class SubscriptionTest? SubscriptionTest?.java:19: cannot find symbol symbol : class Subscription location: class SubscriptionTest? 4 errorsI have create the Subscription class(first program) but as you can see the test program didn't recognize it. Can you help me to run this application?
Hello achourso,
As you compile SubscriptionTest?, the compiler needs Subscription.class but fails to find it. The easiest solution for now is to put both your java files, so Subscription.java and SubscriptionTest?.java in the SAME directory. The compiler will then find your class files without further help.
Of course it is also possible to put them in different directories.
You'll want to correct this line:
assertTrue(S:pricePerMonth() == 1.0) // replace colon with period
You're right. Thanks.
To get the commands in the "Compiling and executing your test" section to work, I changed the semicolons to colons. I seen another article that used colons.
http://www.ibm.com/developerworks/library/j-classpath-unix/
Are the semicolons typos?
I'm using Mac OS X.
junit how to it?
@eshar: it depends on your operating system if you should use ':' or ';' to separate entries in your classpath. The commands in this tutorial are for Windows users. For Linux (and Mac) users the commands should be:
That should also fix achourso's problem.
good and straight to the point
Thank you for writing this quick tutorial, it was really helpful.
Really a big Thanks for this tutorial !!
One thing , java convention again ... When I tweak around with this code to test out JUnit for period of times,
Subscription S = new Subscription(200,2) ; assertTrue(S.pricePerMonth() == 1.0) ;
the "S" naming with uppercase letter keep disturbing me to think that the pricePerMonth() is a static method
anyway , not big issue here
again , THANKS !!!
I think I just need another pair of eyes on this but I am getting an error when I tried to compile SubscriptionTest?. I have everything in the same directory and I downloaded & opened the junit-4.6.jar file, but I keep getting the following errors: "<identifier> expected on the import static org.juinit.Assert.; line 2....
My guess is that you are using java version 1.4; import static is a feature of >= 1.5
I think it's something else because I typed "C:\>java -version", here at home not at work this time, and got the following results: java version "1.6.0_10" Java(TM) SE Runtime Environment (build 1.6.0_10-b33) Java HotSot?(TM) Client VM (build 11.0-b15, mixed mode, sharing)
by the way here is the entire error printout:
C:\Java Workbench\Projects\EmergencyProc?\SubscriptionTest?.java:1: package org.junit does not exist import org.junit. ; ^ C:\Java Workbench\Projects\EmergencyProc?\SubscriptionTest?.java:2: package org.junit does not exist import static org.junit.Assert. ;
C:\Java Workbench\Projects\EmergencyProc?\SubscriptionTest?.java:6: cannot access Test bad class file: .\Test.class class file contains wrong class: org.junit.Test Please remove or make sure it appears in the correct subdirectory of the classpath.Tool completed with exit code 1
thanks
It looks like different errors are now given. It seems like java has a problem in finding your junit ("...package org.junit does not exist..."). I will have to ask this stupid question :), but do you have junit 4.x included in your classpath?
I typed "path" at my c prompt and got the following:
PATH=C:\oraclexe\app\oracle\product\10.2.0\server\bin;C:\WINNT\system32;C:\WINNT;C:\WINNT\system32\WBEM;C:\Program Files\Java\jdk1.5.0_05\jre\bin;C:\Program Files\Java\jdk1.5.0_05\bin;C:\Program Files\\Maestro Learning\Common;C:\Program Files\QuickTime?\QTSystem\;C:\adabas\bin;C:\adabas\pgm;C:\Program Files\Java\jdk1.6.0_10\bin
It's been awhile since I messed with it but I will obviously have to change it.
thanks
Well, there's a bad lesson in here: money shouldn't be stored in a double! That's why someone needed to do some rounds to make it pass. Doubles are for aprox values, and you don't want the aprox amount of euros, you want the exact amount of cents, so store your money in int or long, as cents.
Regards !
Well, in the example it is NOT stored in double, but in int. The class just have a function that express it in double.
Hey, how to generate reports on the list of test cases that failed /passed? Also, is there a way to run only the failed test cases again and merge the results?
First uprime812, i want to thank you so much! Most Junit tutorials are aloof and a little intimidating. The few minutes i spent with yours has really helped me and boosted my confidence. Thank you.
Second, in the compiling and execution test section, i entered in my cmd prompt and received the following: C:\junit\junit4.7>javac -cp .;C:\junit\junit4.7 junit_tut1_tc.java javac: file not found: junit_tut1_tc.java Usage: javac <options> <source files> use -help for a list of possible options
Is their a specific place my file/class junit_tut1_tc.java has to be?
Thanks, MrBCut
C:\junit\junit4.7>javac -cp .;C:\junit\junit4.7 junit_tut1_tc.java
don't forget the jar C:\junit\junit4.7>javac -cp .;C:\junit\junit4.7\junit<version>.jar junit_tut1_tc.java
Thanks for the quick and straight forward tutorial. Very nice jumpstart for an agile newbie.
I get the following error: java.lang.Exception: Test class should have public zero-argument constructor
any suggestions?
Make sure the constructor of you test class doesn't need any arguments.
hi i want to run same testcase for multiple times with different data
for example if i run the same testcase for 3 times with different data it should show
when i tried am getting Tests run : 1 only any suggestions?
Good tut...
sachin sthalekar
Excellent job, I am onto your other tutorials
Good Tutorial
good tutorial
really good tutorial, but it's not very detail referenced to ignore, time test. More details in http://www.javarmi.com/2010/09/junit-tutorials-and-example
Hi Friends, can Any 1 help Me , Why I am getting this error teven though I set path.
C:\Program Files\Java\jdk1.6.0_05\bin>set path="C:\Documents and Settings\220805 \Desktop\junit-4.8.1"
C:\Program Files\Java\jdk1.6.0_05\bin>javac CalculatorTest?.java CalculatorTest?.java:1: package org.junit does not exist import org.junit. ; ^ CalculatorTest?.java:2: package org.junit does not exist import static org.junit.Assert. ;
CalculatorTest?.java:8: cannot find symbol symbol: class TestCase? public class CalculatorTest? extends TestCase? { CalculatorTest?.java:16: cannot find symbol symbol : method assertEquals(int,int) location: class CalculatorTest? 4 errorsgood tutorial
When I tried this example I get this when trying to compile:
==============================================0 ~/java/test$ javac SubscriptionTest?.java SubscriptionTest?.java:7: incompatible types found : Test required: java.lang.annotation.Annotation
SubscriptionTest?.java:14: incompatible types found : Test required: java.lang.annotation.Annotation 2 errorsI cannot see what I have done wrong. I'm using junit-4.8.2.jar and openjdk-6-jdk.
Thank's for the otherwise very good starter.
Thank you for starter on JUnit 4.x.
Classes Subscription and SubscriptionTest? got compiled and executed successfully.
Similar test code I have tried is not getting compiled. It shows 'cannot find symbol' error as shown below:
AnimalTest??.java:11: cannot find symbol symbol : method assetEquals(java.lang.String,java.lang.String,java.lang.String)
location: class AnimalTest??
assetEquals("String returned is not matching with expected", "sound of animal", animalToBeTested.talk()); ^
AnimalTest??.java:18: cannot find symbol symbol : method assetEquals(java.lang.String,java.lang.String,java.lang.String)
location: class AnimalTest??
assetEquals("String returned is not matching with expected", "Animal eats food for animal", animalToBeTested.eat("food for animal")); ^ 2 errors
Code of AnimalTest? is as follows:
import org.junit.; import static org.junit.Assert.;
public class AnimalTest? {
}
Corresponding class Animal got compiled and executed successfully (it has main method).
Files Animal.java, Animal.class and AnimalTest?.java are in same directory.
How to resolve the error ?
I have java version 1.6.0_21 and JUnit version 4.7
@mangeshminal The error tells you that there's no assetEquals method, which is true since it's assertEquals.
Thank you @christiaanhees for pointing out the error. It compiled and executed successfully.
>>Open a console. You first need to compile the test class, and then you can execute it. The commands are (in Windows):
What happen the normal class (Subscription) it want compile or what? When I compile test class SubscriptionTest?.java:16: cannot find symbol symbol : class Subscription location: class SubscriptionTest?
i have successfully compiled the Subscription.java & SubscriptionTest?.java files and get the Class files when i Run the SubscriptionTest? file then i get the message as Exception in Thread "main" java.lang.NoClassDefFoundError?: but i have both the Class file at the current Directoty.
plz help in this
assertTrue(S.pricePerMonth() == 0.67);
Please don't perpetuate this practice. Always use assertEquals when you are checking for equality. The framework will give you much better information if you work with it. For example if you used:
assertEquals(0.67, S.pricePerMonth());
If this fails junit will tell you your expected and actual results without having to look at the code. Yours will simply tell me it failed.
Jason, I think that difference is really superficial. Most likely you will have to inspect the test-case anyway to understand why it fails. Writing it as assertTrue(e1 == e2) makes the expression reads better. Since most of my effort goes to thinking about the logic of the test and later, if it fails, in figuring out why, I really favor code readability.
good article!
how can i write unit test cases for web application ? mainly i would like to know how we can pass HttpServletRequest? object or database matadata to test case?