要求:
编写一个简单的货币基金选择器,考虑以下几种货币类型:CNY(人民币)、USD(美元)、GBP(英镑)、EUR(欧元)、CAD(加元),假设基金选择方法每次选择兑换值最高的货币作为投资目标,实验包括对JUnit和EasyMock的使用,最后给出关键的代码截图和测试用例运行结果。
import java.io.IOException; public interface ExchangeRate { public double getRate(String inputCurrency, String outputCurrency) throws IOException; }
import java.io.IOException; public class Currency { private String unit; private long amount; private int cents; public Currency(double amount,String unit){ this.unit=unit; setAmount(amount); } public void setAmount(double amount2) { this.amount = new Double(amount2).longValue(); this.cents=(int) amount2*100%100; } public Currency toChange(ExchangeRate converter){ String[]u={"CNY","USD","GBP","EUR","CAD"}; String changeUnit=null; double maxRate=0; double temp; try{ for(String tempUnit:u){ temp=converter.getRate(this.unit,tempUnit); if(temp>maxRate) { changeUnit=tempUnit; maxRate=temp; } } if(changeUnit.equals(this.unit)) return this; double input = amount+cents/100.0; return new Currency(input*maxRate,changeUnit); }catch (IOException e) { e.printStackTrace(); return null; } } public boolean equals(Object o){ if(o instanceof Currency){ Currency other =(Currency) o; return this.unit.equals(other.unit) && this.amount==other.amount && this.cents==other.cents; } return false; } public String toString(){ return this.amount+"."+cents+" "+unit; } }
import junit.framework.TestCase; import org.easymock.EasyMock; import org.junit.Test; import java.io.IOException; public class CurrencyTest extends TestCase { @Test public void test() throws IOException { Currency testObject=new Currency(2.5,"USD"); Currency expected=new Currency(3.75,"EUR"); ExchangeRate mockRate= EasyMock.createMock(ExchangeRate.class); EasyMock.expect(mockRate.getRate("USD","USD")).andReturn(1.0); EasyMock.expect(mockRate.getRate("USD","CNY")).andReturn(0.5); EasyMock.expect(mockRate.getRate("USD","GBP")).andReturn(1.1); EasyMock.expect(mockRate.getRate("USD","EUR")).andReturn(1.5); EasyMock.expect(mockRate.getRate("USD","CAD")).andReturn(0.3); EasyMock.replay(mockRate); Currency actual=testObject.toChange(mockRate); assertEquals(actual,expected); } }
{% note warning %}
{% endnote %}
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException{ String username = req.getParameter("username"); String password = req.getParameter("password"); if("admin".equals(username) && "123456".equals(password)) { ServletContext context = getServletContext(); RequestDispatcher dispatcher = context.getNamedDispatcher("dispatcher"); dispatcher.forward(req, res); }else { throw new RuntimeException("Login failed."); } } }
import junit.framework.TestCase; import org.easymock.EasyMock; import org.junit.Before; import org.junit.Test; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; public class TestLoginServlet extends TestCase { private HttpServletRequest request; private ServletContext context; private RequestDispatcher dispatcher; private LoginServlet loginServlet; @Before public void setUp() throws Exception { request= EasyMock.createMock(HttpServletRequest.class); context=EasyMock.createMock(ServletContext.class); dispatcher=EasyMock.createMock(RequestDispatcher.class); loginServlet=new LoginServlet(); } @Test public void testLoginSuccess() throws Exception{ EasyMock.expect(request.getParameter("username")).andReturn("admin"); EasyMock.expect(request.getParameter("password")).andReturn("123456"); EasyMock.expect(context.getNamedDispatcher("dispatcher")).andReturn(dispatcher); dispatcher.forward(request,null); EasyMock.replay(request); EasyMock.replay(context); EasyMock.replay(dispatcher); //匿名类 loginServlet =new LoginServlet(){ public ServletContext getServletContext(){ return context; } }; loginServlet.doPost(request,null); EasyMock.verify(request); EasyMock.verify(context); EasyMock.verify(dispatcher); } @Test public void testLoginFailed1() { EasyMock.expect(request.getParameter("username")).andReturn("ad"); EasyMock.expect(request.getParameter("password")).andReturn("123456"); EasyMock.replay(request); try { loginServlet.doPost(request,null); } catch (Exception e) { assertEquals("Login failed.",e.getMessage()); } EasyMock.verify(request); } @Test public void testLoginFailed2() { EasyMock.expect(request.getParameter("username")).andReturn("admin"); EasyMock.expect(request.getParameter("password")).andReturn("123"); EasyMock.replay(request); try { loginServlet.doPost(request,null); } catch (Exception e) { assertEquals("Login failed.",e.getMessage()); } EasyMock.verify(request); } @Test public void testLoginFailed3() { EasyMock.expect(request.getParameter("username")).andReturn(null); EasyMock.expect(request.getParameter("password")).andReturn("123456"); EasyMock.replay(request); try { loginServlet.doPost(request,null); } catch (Exception e) { assertEquals("Login failed.",e.getMessage()); } EasyMock.verify(request); } @Test public void testLoginFailed4() { EasyMock.expect(request.getParameter("username")).andReturn("admin"); EasyMock.expect(request.getParameter("password")).andReturn(null); EasyMock.replay(request); try { loginServlet.doPost(request,null); } catch (Exception e) { assertEquals("Login failed.",e.getMessage()); } EasyMock.verify(request); } }
{% note warning %}
测试类中之所以用到匿名类,是因为要测试的代码中使用了getServletContext()方法,此方法是Servlet上下文的方法,此处模拟了环境,也应模拟此方法。
How使用匿名类?Java的匿名内部类
{% endnote %}
package org.easymock.demo.domain; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; public interface DBUtility { public abstract Connection getConnection(); public abstract void closeDBResource(Connection conn); public abstract void closeDBResource(Statement stmt); public abstract void closeDBResource(ResultSet rs); }
package org.easymock.demo.domain; import java.sql.ResultSet; import java.sql.SQLException; public interface SalesOrder { public String getOrderNumber(); public String getRegion(); public double getTotalPrice(); public void setOrderNumber(String orderNumber); public void setRegion(String region); public void setTotalPrice(double totalPrice); public void loadDataFromDB(ResultSet resultSet) throws SQLException; public String getPriceLevel(); public String toString(); }
package org.easymock.demo.domain; import java.sql.ResultSet; import java.sql.SQLException; public class SalesOrderImpl implements SalesOrder { private String orderNumber; private String region; private double totalPrice; public String getOrderNumber(){return orderNumber;} public String getRegion(){return region;} public double getTotalPrice(){return totalPrice;} public void setOrderNumber(String orderNumber){this.orderNumber = orderNumber;} public void setRegion(String region){this.region = region;} public void setTotalPrice(double totalPrice){this.totalPrice = totalPrice;} public void loadDataFromDB(ResultSet resultSet) throws SQLException { orderNumber = resultSet.getString(1); region = resultSet.getString(2); totalPrice = resultSet.getDouble(3); } public String getPriceLevel() { double totalPrice = this.getTotalPrice(); double totalPoints = 0.0; if ("Africa".equalsIgnoreCase(this.getRegion())) totalPoints = totalPrice; else if ("Asia Pacific".equalsIgnoreCase(this.getRegion())) totalPoints = totalPrice * 0.9; else if ("Europe".equalsIgnoreCase(this.getRegion())) totalPoints = totalPrice * 0.85; else if ("America".equalsIgnoreCase(this.getRegion())) totalPoints = totalPrice * 0.8; else totalPoints = totalPrice * 0.75; if (totalPoints < 500) return "Level_A"; else if (totalPoints < 1000) return "Level_B"; else if (totalPoints < 2000) return "Level_C"; else if (totalPoints < 4000) return "Level_D"; else return "Level_E"; } public String toString() { StringBuffer sb = new StringBuffer(); sb.append("orderNumber = "+orderNumber+"\n"); sb.append("region = "+region+"\n"); sb.append("totalPrice = "+totalPrice+"\n"); sb.append("priceLevel = "+this.getPriceLevel()+"\n"); return sb.toString(); } }
package org.easymock.demo.testcase; import static org.easymock.EasyMock.expectLastCall; import static org.easymock.demo.matcher.SQLEquals.sqlEquals; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; import junit.framework.TestCase; import org.easymock.EasyMock; import org.easymock.IMocksControl; import org.easymock.demo.domain.DBUtility; import org.easymock.demo.domain.SalesOrder; import org.easymock.demo.domain.SalesOrderImpl; public class SalesOrderTestCase extends TestCase { public void testSalesOrder() { IMocksControl control = EasyMock.createControl(); DBUtility mockDBUtility = control.createMock(DBUtility.class); Connection mockConnection = control.createMock(Connection.class); Statement mockStatement = control.createMock(Statement.class); ResultSet mockResultSet = control.createMock(ResultSet.class); try { mockDBUtility.getConnection(); EasyMock.expectLastCall().andStubReturn(mockConnection); mockConnection.createStatement(); expectLastCall().andStubReturn(mockStatement); mockStatement.executeQuery(sqlEquals("SELECT * FROM sales_order_table")); expectLastCall().andStubReturn(mockResultSet); mockResultSet.next(); expectLastCall().andReturn(true).times(3); expectLastCall().andReturn(false).times(1); mockResultSet.getString(1); expectLastCall().andReturn("DEMO_ORDER_001").times(1); expectLastCall().andReturn("DEMO_ORDER_002").times(1); expectLastCall().andReturn("DEMO_ORDER_003").times(1); mockResultSet.getString(2); expectLastCall().andReturn("Asia Pacific").times(1); expectLastCall().andReturn("Europe").times(1); expectLastCall().andReturn("America").times(1); mockResultSet.getDouble(3); expectLastCall().andReturn(350.0).times(1); expectLastCall().andReturn(1350.0).times(1); expectLastCall().andReturn(5350.0).times(1); control.replay(); Connection conn = mockDBUtility.getConnection(); Statement stat = conn.createStatement(); ResultSet rs = stat.executeQuery("select * from sales_order_table"); int i = 0; String[] priceLevels = { "Level_A", "Level_C", "Level_E" }; while (rs.next()) { SalesOrder order = new SalesOrderImpl(); order.loadDataFromDB(rs); assertEquals(order.getPriceLevel(), priceLevels[i]); i++; } control.verify(); } catch (Exception e) { e.printStackTrace(); } } }
package org.easymock.demo.matcher; import static org.easymock.EasyMock.reportMatcher; import org.easymock.IArgumentMatcher; public class SQLEquals implements IArgumentMatcher { private String expectedSQL = null; public SQLEquals(String expectedSQL) { this.expectedSQL = expectedSQL; } public void appendTo(StringBuffer buffer) { buffer.append("SQLEquals(\"" + expectedSQL + "\")"); } public boolean matches(Object actualSQL) { if (actualSQL == null && expectedSQL == null) return true; else if (actualSQL instanceof String) return expectedSQL.equalsIgnoreCase((String) actualSQL); else return false; } public static String sqlEquals(String in) { reportMatcher(new SQLEquals(in)); return in; } }
Java的匿名内部类