Thursday, September 11, 2008

Partial mocking of objects using easymock classextensions

Ocassionally, some of your methods in your classes need to call some other public methods in the same class to get the job done. But when writing unit tests for the calling methods, you want to keep your tests isolated from the calls to other public methods. I encountered such a scenario recently and found that Easymock can help you by mocking some of the methods while keeping the rest of the methods intact.

Let us see an example,
The BlogSearchService has two public methods, first method filterBlogsByAuthor takes an author name and a list of blogs and returns all the blogs written by that particular order author.
The other business method searchBlogs will take a search paramter and the author, it will get all the blogs by the search parameter using a custom logic and do some other house keeping tasks like sorting them by published date and number of comments and then filter the methods by author.



package com.teja.blogs;

import java.util.Collections;
import java.util.List;

/**
*
* @author Teja
*/

public class BlogSearchService {

public List<Blog> searchBlogs(String searchString, String author){

//do some custom logic here on these blogs like sorting them by posted date.
return filterBlogsByAuthor(author, Collections.EMPTY_LIST);
}

public List<Blog> filterBlogsByAuthor(String author, List<Blog> blogs){
return Collections.EMPTY_LIST;
}

}

When writing the test cases for the second method, I don't want to test the other public method filterByAuthor as
(i)it has already been tested by other test cases,
(ii)I want to keep my test cases more unit.

So in my test case where I am testing my searchBlogs, I am creating the mock service class which has mock methods only for filterBlogsByAuthor, but the actual mehtod(searchBlogs) which is about to be tested is not.
As usual you can do expectations on the mock class, replay and verify as if it is some other external resource being mocked.

To create a partial mock class of the service, the extra parameter you need to pass is the name of the method to be mocked and the parameter types it accepts (coz, it need to know which version of the method you want to mock if you have overloaded methods)

Here is our test class:



package com.teja.blogs;

import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.easymock.classextension.EasyMock;

/**
*
* @author Teja
*/

public class BlogSearchServiceTest {

@Test
public void testSearchBlogs() throws NoSuchMethodException {
String author = "Teja";
BlogSearchService blogSearchService =EasyMock.createMock(BlogSearchService.class,
BlogSearchService.class.getMethod("filterBlogsByAuthor", new Class[]{String.class, List.class}));
EasyMock.expect(blogSearchService.filterBlogsByAuthor(author, Collections.EMPTY_LIST)).andReturn(Collections.EMPTY_LIST);
EasyMock.replay(blogSearchService);
blogSearchService.searchBlogs("easymock", author);
EasyMock.verify(blogSearchService);
}

}

Saturday, September 6, 2008

Pagination in rails using will_paginate

Pagination is a technique of presenting large amount of data on the UI, allowing the users to navigate between pages/data in an easy way.
Being a java developer for so many years, I remember doing dirty logic to achieve pagination to using some very useful and advanced tag libraries like displaytag. What ever may be the technique, pagination is never been an easy task.
But when I started playing around with rails and I got a situation where I need to do some pagination. And I readily found a gem will_paginate and doing pagination on rails is a breeze.

Lets get started first by installing the gem.





sudo gem install will_paginate

To check whether the plugin installed successfully or not, you can do the following in your rails console.



1
2
3
defined? WillPaginate
[].paginate
ActiveRecord::Base.respond_to? :paginate


Now lets add pagination support to an imaginary page listing all the clients



1
2
3
  def list_clients
@clients = Client.paginate(:page => params[:page], :per_page => 5)
end
and then render the pagination in the ui using this simple snippet



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<h3>Clients</h3>

<%= will_paginate @clients %>
<!--Loop through all the clients and printem-->
<table width=100% cellpadding=0 cellspacing=0 border=0>
<% for @client in @clients do%>
<tr class='client_details'>
<td align='center'><%=@client.client_name.upcase%><
/
td>
<td>
<%=@client.address_line_1%>,<%=@client.address_line_2%><br />
<%=@client.city%>,<%=@client.state%>,<%=@client.zip%>
<
/
td>
</tr>
<%end%>
<
/
table>


The code <%= will_paginate @clients %> will add the links to previous/next page along with the page numbers to naviage.
The next few lines of code is just to print the client details.