JUnit Basics
What is JUnit :
*) is a java unit testing framework used to test java code even at minute level.
*) Junit ensure code coverage of the written code.
What is Test Case ? What is Test Case Method ?
*)
Naming Conventions to write Test Case & Test Case Method ?
Java class
~~~~~~~~
class LoanEligibility {
public void processLoan(Account acc){
// code
}
// it will set priority b/w 1 to 10 only
public boolean setPriority(int p)throws NegativePriorityException{
// Code to set priority to underlying thread
}
}
Unit Testing Conventions :
class LoanEligibilityTest {
LoanEligibility le;
@BeforeClass
public void static createLoanEligibitlityObject(){
le=new LoanEligibility();
}
@Test
public boolean testSetPriorityByIntBetween1to10(){
//LoanEligibility le=new LoanEligibility();
boolean val=le.setPriority(5);
assertEquals(true,val);
//le=null;
}
@Ignore
@Test(exception=NegativePriorityException)
public boolean testSetPriorityByIntNegatives(){
//LoanEligibility le=new LoanEligibility();
le.setPriority(-20);
//le=null;
}
@AfterClass
public void static freeMemoryForLoanElibility(){
le=null;
}
}
JUnit4.0 Annotations :
@Test
public void method() : The Test annotation indicates that the public void method to which it is attached can be run as a test case.
@Before
public void method() : The Before annotation indicates that this method must be executed before each test in the class, so as to execute some preconditions necessary for the test.
@BeforeClass
public static void method() : The BeforeClass annotation indicates that the static method to which is attached must be executed once and before all tests in the class. That happens when the test methods share computationally expensive setup (e.g. connect to database).
@After
public void method() : The After annotation indicates that this method gets executed after execution of each test (e.g. reset some variables after execution of every test, delete temporary variables etc)
@AfterClass
public static void method() : The AfterClass annotation can be used when a method needs to be executed after executing all the tests in a JUnit Test Case class so as to clean-up the expensive set-up (e.g disconnect from a database). Attention: The method attached with this annotation (similar to BeforeClass) must be defined as static.
@Ignore
public static void method() : The Ignore annotation can be used when you want temporarily disable the execution of a specific test. Every method that is annotated with @Ignore won’t be executed.
JUnit Assertions :
i) void assertEquals([String message], expected value, actual value) : Asserts that two values are equal. Values might be type of int, short, long, byte, char or java.lang.Object. The first argument is an optional String message.
public String getName(){
}
ii) void assertTrue([String message], boolean condition): Asserts that a condition is true.
iii)void assertFalse([String message],boolean condition): Asserts that a condition is false.
public boolean isAddress(){
}
iv) void assertNotNull([String message], java.lang.Object object) : Asserts that an object is not null.
v) void assertNull([String message], java.lang.Object object) : Asserts that an object is null.
public Address getAddress(){
//
}
vi) void assertSame([String message], java.lang.Object expected, java.lang.Object actual) : Asserts that the two objects refer to the same object.
vii) void assertNotSame([String message], java.lang.Object unexpected, java.lang.Object actual) : Asserts that the two objects do not refer to the same object.
viii) void assertArrayEquals([String message], expectedArray, resultArray) : Asserts that the array expected and the resulted array are equal. The type of Array might be int, long, short, char, byte or java.lang.Object.
public int[] getPhoneNumbers(){
//
}
Example with Assertions :
import static org.junit.Assert.*;
import org.junit.Test;
public class AssertionsTest {
@Test
public void testExample() {
String obj1 = "junit";
String obj2 = "junit";
String obj3 = "test";
String obj4 = "test";
String obj5 = null;
int var1 = 1;
int var2 = 2;
int[] arithmetic1 = { 1, 2, 3 };
int[] arithmetic2 = { 1, 2, 3 };
assertEquals(obj1, obj2); //test case success
assertSame(obj3, obj4);//test case success
assertNotSame(obj2, obj4); // test case success
assertNotNull(obj1); //test case success
assertNull(obj5);//success
assertTrue(var1 , var2); //fail
assertArrayEquals(arithmetic1, arithmetic2);//success
}
}
Testing with assertEquls
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class TestJunit {
@Test
public void testAdd() {
String str= "Junit is working fine";
assertEquals("Junit is working fine",str);
}
}
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
public class TestRunner {
public static void main(String[] args) {
Result result = JUnitCore.runClasses(TestJunit.class);
for (Failure failure : result.getFailures()) {
System.out.println(failure.toString());
}
System.out.println(result.wasSuccessful());
}
}
Testing with assertTrue, assertFalse
assertTrue(obj.method());//success
assertFalse(false); // success
assertFalse(true);//fail
assertFalse(false);//true
Testing Arrays with assertArrayEquals:
@Test
public void testArraysSort(){
int []numbers= {3,4,2,1,5};
Arrays.sort(numbers);
int[] expected={1,2,3,4,5};
assertArrayEquals(expected,numbers);
}//success
Testing num with assertNull
assertNull(null);//success
assertNotNull(null);//fail
Testing Exceptions with test Expected:
@Test(expected=NullPointerException.class)
public void testArraysSortWithNullCondition(){
int []arrays= null;
Arrays.sort(null);
}
Test @Ignore
Ignore testing method will be ignored and won’t be executed.
@Ignore
@Test
public void testAdd(){
//
}
Testing Performance with test timeout
Can test the method execution with total time taken.
Ex:
@Test(timeout=10)
public void testArraysSortPerformance(){
for(int i=0;i<=1000;i++){
int[] numbers={i,i-1,i+1};
Arrays.sort(numbers);
}
}
Example
@Test(timeout=130)
public void testProcessMultipleRequestsTimeout(){
Request request;
Response response= new SampleResponse();
RequestHandler handler = new SampleHandler();
for(int i=0; i< re.length(); i++){
request = new SampleRequest(String.valueOf(i));
controller.addHandler(request, handler);
response = controller.processRequest();
assertNotNull(response);
assertNotSame(ErrorResponse.class, response.getClass());
}
}
Testing Servlets with JUNIT:
public class MyServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String string1 = request.getParameter("string1");
String string2 = request.getParameter("string2");
String string3 = request.getParameter("string3");
String concatenated =
string1 + "," +
string2 + "," +
string3;
response.getWriter().write(concatenated);
response.getWriter().flush();
}
}
The real business logic really only consists of the concatenation logic. The rest is what I call "dispatch" logic, or "boundary" logic. So, I will take the concatenation logic and move into a separate class, which can be tested independent from the MyServlet class.
The changed code is marked in bold.
public class MyServlet extends HttpServlet {
protected void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {
String string1 = request.getParameter("string1");
String string2 = request.getParameter("string2");
String string3 = request.getParameter("string3");
String concatenated =
MyConcatenator.concatenate(
string1, string2, string3);
response.getWriter().write(concatenated);
response.getWriter().flush();
}
}
public class MyConcatenator {
public static String concatenate(String ... strings){
StringBuilder builder = new StringBuilder();
for(int i = 0; i<strings.length; i++){
if(i>0){
builder.append(",");
}
builder.append(strings[i]);
}
return builder.toString();
}
}
Notice how the concatenate() method only refers to a string array. No references to servlet specific interfaces. That makes it very easy to write a unit test for the MyConcatenator separately. Here is such a unit test:
import org.junit.Test;
import static junit.framework.Assert.*;
public class MyConcatenatorTest {
@Test
public void testConcatenate(){
String concatenated =
MyConcatenator.concatenate(
"one", "two", "three", "four");
assertEquals("one,two,three,four", concatenated);
}
}
JUNIT - Matchers
Matchers :
assertThat():
The assertThat() method compares an object to an org.hamcrest.Matcher to see if the given object matches whatever the Matcher requires it to match.
i) Core Matchers
Before you start implementing your own Matcher's, you should look at the core matchers that come with JUnit already. Here is a list of the matcher methods:
Core :
any() Matches anything
is() A matcher that checks if the given objects are equal.
describedAs() Adds a descrption to a Matcher
Logical :
allOf() Takes an array of matchers, and all matchers must match the target object.
anyOf() Takes an array of matchers, and at least one of the matchers must report that it matches the target object.
not() Negates the output of the previous matcher.
Object :
equalTo() A matcher that checks if the given objects are equal.
instanceOf() Checks if the given object is of type X or is compatible with type X
notNullValue() + nullValue() Tests whether the given object is null or not null.
sameInstance() Tests if the given object is the exact same instance as another.
Actually, all of the above are static methods which take different parameters, and return a Matcher.
You will have to play around with matchers a little, before you get the hang of them. They can be quite handy.
ii) Custom Matchers
You can write your own matchers and plug into the assertThat() method. Here is an example:
public static Matcher matches(final Object expected){
return new BaseMatcher() {
protected Object theExpected = expected;
public boolean matches(Object o) {
return theExpected.equals(o);
}
public void describeTo(Description description) {
description.appendText(theExpected.toString());
}
};
}
The static method matches() creates a new matcher and returns it.
This matcher is an anonymous subclass of the class BaseMatcher. The JUnit documentation states that you should always extend BasreMatcher rather than implement the Matcher interface yourself. Thus, if new methods are added to Matcher in the future, BaseMatcher can implement them. Your subclasses will then automatically get those methods too. That will avoid breaking your code.
Here is how to use this custom matcher:
@Test
public void testThat() {
MyUnit myUnit = new MyUnit();
assertThat(myUnit.getTheSameObject(), matches("constant string"));
}
iii) Chaining Matchers
You can chain some matchers, for instance like this:
@Test
public void testWithMatchers() {
assertThat(123, not( is(345) ) );
}
Notice the chained call not( is(345) ). This is really two matchers combined. The is() method returns one matcher, and the not() method returns another. The matcher returned by not() negates the matcher output of the matcher given as input. In this case, it is the output of the matcher returned by the is() method, that is negated.
Java Relatime Testing code
Story Card : if the given user is friend of LoggedIn User then return the trip list of given user, otherwise throw UserNotLoggedInException
1) public class TripService {
2) public List<Trip> getTripByService(User user)throws UserNotLoggedInException{
3) List<Trip> tripList=new ArrayList<Trip>();
4) User loggedUser=UserSession.getInstance().getLoggedUser();
5) boolean isFriend=false;
6) if(loggedUser!=null){
7) for(User frined:user.getFriends()){
8) if(friend.equals(loggedUser)){
9) isFriend=true;
10) break;
11) }
12) }
13) if(isFriend){
14) tripList=TripDAO.findTripsByUser(user);
15) }
16) return tripList;
17) }else {
18) throw new UserNotLoggedInException();
19) }
20) }
21)}
The method which need to replace for line 4th
4th line should be as : User loggedUser=getLoggedInUser();
protected User getLoggedInUser(){
return UserSession.getInstance().getLoggedUser();
}
Note : the above method should be protected becz it can override by TestCase class to return value.
The method which need to replace for line 14th
14the line should be as : tripList=tripsBy(user);
protected List<Trip> tripsBy(User user){
return TripDAO.findTripsByUser(user);
}
Note : the above method should be protected becz it can override by TestCase class to return value.
Test Case class to test the above TripService :
public class TripServiceTest{
@Test(expected=UserNotLoggedInException.class)
pubic void should_throw_on_exception_when_user_is_not_logged_in(){
TripService tripService=new TestableTripService();
tripService=getTripByUser(null);
}
@Test
public void should_not_return_any_trips_when_users_are_not_friends(){
TripService tripService=new TestableTripService();
loggedUser=new User();
User friend=new User();
friend.addFriend(new User());
friend.addTrip(new Trip());
List<Trip>friendTrips=tripService.getTripByUser(friend);
assertThat(friendTrips.size(),is(0));
}
private class TestableTripService extends TripService{
@Override
protected User getLoggedInUser(){
return null;
}
@Override
protected List<Trip>tripsBy(User user){
return null;
}
}
}
UserSession.java
public class UserSession{
public static final userSession = new UserSession();
public UserSession getInstance(){
return userSession;
}
public User getLoggedUser(){
//code to get Current Logged in User.
}
}
TripDAO.java
public class TripDAO{
public static List<Trip> findTripsByUser(User user){
//Code connect to DB, return Trip List , if User exist.
}
}
User.java
public class User{
private List<Trip> trips=new ArrayList<Trip>();
private List<User> friends=new ArrayList<User>();
public List<User> getFriends(){
return friends;
}
public void addFriend(User user){
friends.add(user);
}
public void addTrip(Trip trip){
trips.add(trip);
}
public List<Trip>trips(){
return trips;
}
}
Note : in the above TripService class instead of writing for loops to get FriendsList, we can add method which ensure the same in User.java class
public boolean isFriendsWith(User anotherUser){
return friends.contains(anotherUser);
}
So in TestCase.java class the for loop is replaces as
public class TripService{
public List<Trip> getTripByService(User user)throws UserNotLoggedInException{
if(getLoggedInUser()==null){
throw new UserNotLoggedInException();
}
return user.isFriendsWith(getLoggedInUser())?tripsBy(user):noTrips();
}
private ArrayList<Trip>noTrips(){
return new ArrayList<Trip>();
}
}
What is JUnit :
*) is a java unit testing framework used to test java code even at minute level.
*) Junit ensure code coverage of the written code.
What is Test Case ? What is Test Case Method ?
*)
Naming Conventions to write Test Case & Test Case Method ?
Java class
~~~~~~~~
class LoanEligibility {
public void processLoan(Account acc){
// code
}
// it will set priority b/w 1 to 10 only
public boolean setPriority(int p)throws NegativePriorityException{
// Code to set priority to underlying thread
}
}
Unit Testing Conventions :
class LoanEligibilityTest {
LoanEligibility le;
@BeforeClass
public void static createLoanEligibitlityObject(){
le=new LoanEligibility();
}
@Test
public boolean testSetPriorityByIntBetween1to10(){
//LoanEligibility le=new LoanEligibility();
boolean val=le.setPriority(5);
assertEquals(true,val);
//le=null;
}
@Ignore
@Test(exception=NegativePriorityException)
public boolean testSetPriorityByIntNegatives(){
//LoanEligibility le=new LoanEligibility();
le.setPriority(-20);
//le=null;
}
@AfterClass
public void static freeMemoryForLoanElibility(){
le=null;
}
}
JUnit4.0 Annotations :
@Test
public void method() : The Test annotation indicates that the public void method to which it is attached can be run as a test case.
@Before
public void method() : The Before annotation indicates that this method must be executed before each test in the class, so as to execute some preconditions necessary for the test.
@BeforeClass
public static void method() : The BeforeClass annotation indicates that the static method to which is attached must be executed once and before all tests in the class. That happens when the test methods share computationally expensive setup (e.g. connect to database).
@After
public void method() : The After annotation indicates that this method gets executed after execution of each test (e.g. reset some variables after execution of every test, delete temporary variables etc)
@AfterClass
public static void method() : The AfterClass annotation can be used when a method needs to be executed after executing all the tests in a JUnit Test Case class so as to clean-up the expensive set-up (e.g disconnect from a database). Attention: The method attached with this annotation (similar to BeforeClass) must be defined as static.
@Ignore
public static void method() : The Ignore annotation can be used when you want temporarily disable the execution of a specific test. Every method that is annotated with @Ignore won’t be executed.
JUnit Assertions :
i) void assertEquals([String message], expected value, actual value) : Asserts that two values are equal. Values might be type of int, short, long, byte, char or java.lang.Object. The first argument is an optional String message.
public String getName(){
}
ii) void assertTrue([String message], boolean condition): Asserts that a condition is true.
iii)void assertFalse([String message],boolean condition): Asserts that a condition is false.
public boolean isAddress(){
}
iv) void assertNotNull([String message], java.lang.Object object) : Asserts that an object is not null.
v) void assertNull([String message], java.lang.Object object) : Asserts that an object is null.
public Address getAddress(){
//
}
vi) void assertSame([String message], java.lang.Object expected, java.lang.Object actual) : Asserts that the two objects refer to the same object.
vii) void assertNotSame([String message], java.lang.Object unexpected, java.lang.Object actual) : Asserts that the two objects do not refer to the same object.
viii) void assertArrayEquals([String message], expectedArray, resultArray) : Asserts that the array expected and the resulted array are equal. The type of Array might be int, long, short, char, byte or java.lang.Object.
public int[] getPhoneNumbers(){
//
}
Example with Assertions :
import static org.junit.Assert.*;
import org.junit.Test;
public class AssertionsTest {
@Test
public void testExample() {
String obj1 = "junit";
String obj2 = "junit";
String obj3 = "test";
String obj4 = "test";
String obj5 = null;
int var1 = 1;
int var2 = 2;
int[] arithmetic1 = { 1, 2, 3 };
int[] arithmetic2 = { 1, 2, 3 };
assertEquals(obj1, obj2); //test case success
assertSame(obj3, obj4);//test case success
assertNotSame(obj2, obj4); // test case success
assertNotNull(obj1); //test case success
assertNull(obj5);//success
assertTrue(var1 , var2); //fail
assertArrayEquals(arithmetic1, arithmetic2);//success
}
}
Testing with assertEquls
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class TestJunit {
@Test
public void testAdd() {
String str= "Junit is working fine";
assertEquals("Junit is working fine",str);
}
}
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
public class TestRunner {
public static void main(String[] args) {
Result result = JUnitCore.runClasses(TestJunit.class);
for (Failure failure : result.getFailures()) {
System.out.println(failure.toString());
}
System.out.println(result.wasSuccessful());
}
}
Testing with assertTrue, assertFalse
assertTrue(obj.method());//success
assertFalse(false); // success
assertFalse(true);//fail
assertFalse(false);//true
Testing Arrays with assertArrayEquals:
@Test
public void testArraysSort(){
int []numbers= {3,4,2,1,5};
Arrays.sort(numbers);
int[] expected={1,2,3,4,5};
assertArrayEquals(expected,numbers);
}//success
Testing num with assertNull
assertNull(null);//success
assertNotNull(null);//fail
Testing Exceptions with test Expected:
@Test(expected=NullPointerException.class)
public void testArraysSortWithNullCondition(){
int []arrays= null;
Arrays.sort(null);
}
Test @Ignore
Ignore testing method will be ignored and won’t be executed.
@Ignore
@Test
public void testAdd(){
//
}
Testing Performance with test timeout
Can test the method execution with total time taken.
Ex:
@Test(timeout=10)
public void testArraysSortPerformance(){
for(int i=0;i<=1000;i++){
int[] numbers={i,i-1,i+1};
Arrays.sort(numbers);
}
}
Example
@Test(timeout=130)
public void testProcessMultipleRequestsTimeout(){
Request request;
Response response= new SampleResponse();
RequestHandler handler = new SampleHandler();
for(int i=0; i< re.length(); i++){
request = new SampleRequest(String.valueOf(i));
controller.addHandler(request, handler);
response = controller.processRequest();
assertNotNull(response);
assertNotSame(ErrorResponse.class, response.getClass());
}
}
Testing Servlets with JUNIT:
public class MyServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String string1 = request.getParameter("string1");
String string2 = request.getParameter("string2");
String string3 = request.getParameter("string3");
String concatenated =
string1 + "," +
string2 + "," +
string3;
response.getWriter().write(concatenated);
response.getWriter().flush();
}
}
The real business logic really only consists of the concatenation logic. The rest is what I call "dispatch" logic, or "boundary" logic. So, I will take the concatenation logic and move into a separate class, which can be tested independent from the MyServlet class.
The changed code is marked in bold.
public class MyServlet extends HttpServlet {
protected void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {
String string1 = request.getParameter("string1");
String string2 = request.getParameter("string2");
String string3 = request.getParameter("string3");
String concatenated =
MyConcatenator.concatenate(
string1, string2, string3);
response.getWriter().write(concatenated);
response.getWriter().flush();
}
}
public class MyConcatenator {
public static String concatenate(String ... strings){
StringBuilder builder = new StringBuilder();
for(int i = 0; i<strings.length; i++){
if(i>0){
builder.append(",");
}
builder.append(strings[i]);
}
return builder.toString();
}
}
Notice how the concatenate() method only refers to a string array. No references to servlet specific interfaces. That makes it very easy to write a unit test for the MyConcatenator separately. Here is such a unit test:
import org.junit.Test;
import static junit.framework.Assert.*;
public class MyConcatenatorTest {
@Test
public void testConcatenate(){
String concatenated =
MyConcatenator.concatenate(
"one", "two", "three", "four");
assertEquals("one,two,three,four", concatenated);
}
}
JUNIT - Matchers
Matchers :
assertThat():
The assertThat() method compares an object to an org.hamcrest.Matcher to see if the given object matches whatever the Matcher requires it to match.
i) Core Matchers
Before you start implementing your own Matcher's, you should look at the core matchers that come with JUnit already. Here is a list of the matcher methods:
Core :
any() Matches anything
is() A matcher that checks if the given objects are equal.
describedAs() Adds a descrption to a Matcher
Logical :
allOf() Takes an array of matchers, and all matchers must match the target object.
anyOf() Takes an array of matchers, and at least one of the matchers must report that it matches the target object.
not() Negates the output of the previous matcher.
Object :
equalTo() A matcher that checks if the given objects are equal.
instanceOf() Checks if the given object is of type X or is compatible with type X
notNullValue() + nullValue() Tests whether the given object is null or not null.
sameInstance() Tests if the given object is the exact same instance as another.
Actually, all of the above are static methods which take different parameters, and return a Matcher.
You will have to play around with matchers a little, before you get the hang of them. They can be quite handy.
ii) Custom Matchers
You can write your own matchers and plug into the assertThat() method. Here is an example:
public static Matcher matches(final Object expected){
return new BaseMatcher() {
protected Object theExpected = expected;
public boolean matches(Object o) {
return theExpected.equals(o);
}
public void describeTo(Description description) {
description.appendText(theExpected.toString());
}
};
}
The static method matches() creates a new matcher and returns it.
This matcher is an anonymous subclass of the class BaseMatcher. The JUnit documentation states that you should always extend BasreMatcher rather than implement the Matcher interface yourself. Thus, if new methods are added to Matcher in the future, BaseMatcher can implement them. Your subclasses will then automatically get those methods too. That will avoid breaking your code.
Here is how to use this custom matcher:
@Test
public void testThat() {
MyUnit myUnit = new MyUnit();
assertThat(myUnit.getTheSameObject(), matches("constant string"));
}
iii) Chaining Matchers
You can chain some matchers, for instance like this:
@Test
public void testWithMatchers() {
assertThat(123, not( is(345) ) );
}
Notice the chained call not( is(345) ). This is really two matchers combined. The is() method returns one matcher, and the not() method returns another. The matcher returned by not() negates the matcher output of the matcher given as input. In this case, it is the output of the matcher returned by the is() method, that is negated.
Java Relatime Testing code
Story Card : if the given user is friend of LoggedIn User then return the trip list of given user, otherwise throw UserNotLoggedInException
1) public class TripService {
2) public List<Trip> getTripByService(User user)throws UserNotLoggedInException{
3) List<Trip> tripList=new ArrayList<Trip>();
4) User loggedUser=UserSession.getInstance().getLoggedUser();
5) boolean isFriend=false;
6) if(loggedUser!=null){
7) for(User frined:user.getFriends()){
8) if(friend.equals(loggedUser)){
9) isFriend=true;
10) break;
11) }
12) }
13) if(isFriend){
14) tripList=TripDAO.findTripsByUser(user);
15) }
16) return tripList;
17) }else {
18) throw new UserNotLoggedInException();
19) }
20) }
21)}
The method which need to replace for line 4th
4th line should be as : User loggedUser=getLoggedInUser();
protected User getLoggedInUser(){
return UserSession.getInstance().getLoggedUser();
}
Note : the above method should be protected becz it can override by TestCase class to return value.
The method which need to replace for line 14th
14the line should be as : tripList=tripsBy(user);
protected List<Trip> tripsBy(User user){
return TripDAO.findTripsByUser(user);
}
Note : the above method should be protected becz it can override by TestCase class to return value.
Test Case class to test the above TripService :
public class TripServiceTest{
@Test(expected=UserNotLoggedInException.class)
pubic void should_throw_on_exception_when_user_is_not_logged_in(){
TripService tripService=new TestableTripService();
tripService=getTripByUser(null);
}
@Test
public void should_not_return_any_trips_when_users_are_not_friends(){
TripService tripService=new TestableTripService();
loggedUser=new User();
User friend=new User();
friend.addFriend(new User());
friend.addTrip(new Trip());
List<Trip>friendTrips=tripService.getTripByUser(friend);
assertThat(friendTrips.size(),is(0));
}
private class TestableTripService extends TripService{
@Override
protected User getLoggedInUser(){
return null;
}
@Override
protected List<Trip>tripsBy(User user){
return null;
}
}
}
UserSession.java
public class UserSession{
public static final userSession = new UserSession();
public UserSession getInstance(){
return userSession;
}
public User getLoggedUser(){
//code to get Current Logged in User.
}
}
TripDAO.java
public class TripDAO{
public static List<Trip> findTripsByUser(User user){
//Code connect to DB, return Trip List , if User exist.
}
}
User.java
public class User{
private List<Trip> trips=new ArrayList<Trip>();
private List<User> friends=new ArrayList<User>();
public List<User> getFriends(){
return friends;
}
public void addFriend(User user){
friends.add(user);
}
public void addTrip(Trip trip){
trips.add(trip);
}
public List<Trip>trips(){
return trips;
}
}
Note : in the above TripService class instead of writing for loops to get FriendsList, we can add method which ensure the same in User.java class
public boolean isFriendsWith(User anotherUser){
return friends.contains(anotherUser);
}
So in TestCase.java class the for loop is replaces as
public class TripService{
public List<Trip> getTripByService(User user)throws UserNotLoggedInException{
if(getLoggedInUser()==null){
throw new UserNotLoggedInException();
}
return user.isFriendsWith(getLoggedInUser())?tripsBy(user):noTrips();
}
private ArrayList<Trip>noTrips(){
return new ArrayList<Trip>();
}
}