Background
EasyMock has been the first dynamic Mock Object
generator, relieving users of hand-writing Mock Objects, or generating
code for them.
EasyMock provides Mock Objects by generating them on the fly using Java's proxy mechanism.
We are going to use this to write test cases in Java. For more details you can visit their official website.
Adding Dependencies
As usual I am going to use Ivy to add dependencies to my project (Installing and using Apache Ivy as dependency manager). You ivy.xml should look something like the following -
<?xml version="1.0" encoding="ISO-8859-1"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <ivy-module version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd"> <info organisation="openSourceForGeeks" module="EasyMockDemo" status="integration"> </info> <dependencies> <dependency org="junit" name="junit" rev="4.11"/> <dependency org="org.easymock" name="easymock" rev="3.1"/> </dependencies> </ivy-module>
What we want to achieve via this testing and Why...
Consider you have developed a online shopping portal. You have a class Product that holds information of your individual product like its name and quantity. When you shop you would purchase multiple products. So lets have a class ShoppingBasket that holds a List of Products. Also lets have a service ShoppingService that would calculate total cost of all the product in the ShoppingBasket. In production code you would probably have this service make a database call the get the price of the product but we cannot afford that in the tests. So we will mock this service and use it instead of an actual DB call.
Thats it run the method with annotation @test using junit. Your test should be successful.To the code.....
First create a class Product.java
public class Product { private String name; private int quantity; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getQuantity() { return quantity; } public void setQuantity(int quantity) { this.quantity = quantity; } }
Then create a class name ShoppingBasket.java
public class ShoppingBasket { private String basketName; private ShoppingService shoppingService; private List<Product> products = new ArrayList<Product>(); public int getTotalCost() { int totalCost = 0; for(Product product: products) { totalCost = totalCost + shoppingService.getProductCost(product.getName()); } return totalCost; } public void addProduct(Product product) { this.products.add(product); } public String getBasketName() { return basketName; } public void setBasketName(String basketName) { this.basketName = basketName; } public ShoppingService getShoppingService() { return shoppingService; } public void setShoppingService(ShoppingService shoppingService) { this.shoppingService = shoppingService; } public List<Product> getProducts() { return products; } public void setProducts(List<Product> products) { this.products = products; } }
Noe create a Service (which would be an interface / production code would have this implementation with DB logic) name ShoppingService.java.
public interface ShoppingService { int getProductCost(String productName); }
Note : Methods in an interface are bu default public and abstract. Whereas variable are by default public, static and final.
Finally create a Test class that mocks the service and tests out the getProductCost() method.
import org.easymock.EasyMock; import org.junit.Before; import org.junit.Test; import junit.framework.Assert; import junit.framework.TestCase; public class ShoppingBasketTest{ private ShoppingBasket shoppingBasket; private ShoppingService shoppingServiceMock; @Before public void init(){ shoppingBasket = new ShoppingBasket(); shoppingBasket.setBasketName("myBaset"); shoppingServiceMock = EasyMock.createMock(ShoppingService.class); shoppingBasket.setShoppingService(shoppingServiceMock); } @Test public void testTotalCost(){ EasyMock.expect(shoppingServiceMock.getProductCost("Moto E Android Smartphone")).andReturn(7000); EasyMock.replay(shoppingServiceMock); Product motoE = new Product(); motoE.setName("Moto E Android Smartphone"); shoppingBasket.addProduct(motoE); Assert.assertEquals(7000, shoppingBasket.getTotalCost()); } }
Note : If you make your test class extend TestCase class @before annotation will not work. If you extend TestCase, JUnit treats your test class as an old (pre JUnit 4 class) and picks
org.junit.internal.runners.JUnit38ClassRunner
to run it. JUnit38ClassRunner does not know about @BeforeClass
annotation. You have to put you logic in overridden method setUp().