Upgrade to Pro — share decks privately, control downloads, hide ads and more …

EasyMock Tech Talk

McManCSU
August 29, 2013

EasyMock Tech Talk

Tech Talk with loads of bite size examples

McManCSU

August 29, 2013
Tweet

More Decks by McManCSU

Other Decks in Technology

Transcript

  1. Agenda • Overview • Mocks & Expects • Replaying •

    Verifying • Advanced Expects • Partial Mocks • Strict Mocks • Captures • PowerMock • General Tips Thursday, August 29, 13
  2. Overview • Java test library • Groovy works with some

    effort • Integrates into JUnit test cases • Test driven development • Achieve high code/branch coverage • Cobertura and other plugins Thursday, August 29, 13
  3. General Outline @Test public testMyMock() { // Create mocks //

    Establish expectations // Replay mocks EasyMock.replay(mock1, mock2, ...); // Execute test case // Verify mocks EasyMock.verify(mock1, mock2, ...); } Thursday, August 29, 13
  4. Mocks • Easily abstracted, wrapped Object • Define specific behaviors,

    for certain scenarios on the Mocked Object • Validate the expected behaviors • Enables granular testing • Can achieve 100% source & branch coverage Thursday, August 29, 13
  5. Mocks Example SimpleClass simple; @Before public void setup() { //

    Useful for commonly used mocks. // Reset between tests. simple = EasyMock.createMock(SimpleClass.class); } @Test public void testMethod() { // Mock specific to this test only Complex complex = EasyMock.createMock(Complex.class); ... } Thursday, August 29, 13
  6. Expectations • Winding up the Mocks • Establish return values

    • Throw exceptions • Check/capture method params • Void method expectations • Chain expectations together - Caution! Thursday, August 29, 13
  7. Expectations Example import static org.easymock.EasyMock.*; @Test public void testPerform() {

    Complex complex = createMock(Complex.class); // Simple expect - perform() returns a String expect(complex.perform()).andReturn(“that was easy”); // Simple throw exception expect(complex.perform()).andThrow(new WTFException()); // Ordered chain - 3 expectations expect(complex.perform()) .andReturn(“hard”) .andReturn(“easy”) .andThrow(new WTFException()); ... } Thursday, August 29, 13
  8. Expectations Example cont. import static org.easymock.EasyMock.*; @Test public void testCompute()

    { Complex complex = createMock(Complex.class); // 1) Simple expect - setup() is a void method complex.setup(); expectLastCall(); // Optional for a single call // 2) Back-to-back setup calls complex.setup(); complex.setup(); complex.setup(); // 3) Simplified version of 2) - they are equivalent complex.setup(); expectLastCall().times(3); } Thursday, August 29, 13
  9. Replay • Post expectations, ‘replay’ each mock • Preps mock

    object for test execution • Required to use mock object • Will get NPE, otherwise Thursday, August 29, 13
  10. Verify • Verify that all expectations were met • Optional,

    though should be required!! • Without, not all expectations have to be met for tests to pass • Inadvertently miss intended expects • Between each @Test mocks are reset Thursday, August 29, 13
  11. Advanced Expectations • How about checking params passed into the

    mocked methods? • Specify a .equals() equivalent value • Matchers • aryEq(someArray), isA(xxx.class) • eq(xxx), anyPrimitive() - (int, long, boolean) “If you would like to use matchers in a call, you have to specify matchers for all arguments of the method call.” Thursday, August 29, 13
  12. Advanced Expectations Ex. import static org.easymock.EasyMock.*; @Test public void testCompute()

    { Adder adder = createMock(Adder.class); // 1) Specific values expect expect(adder.add(1, 2)).andReturn(3); // 2) Any type of int - boundary condition of -1 expect(adder.add(anyInt(), anyInt()).andReturn(-1); // 3) Class-wise generic - again, boundary condition of -1 expect(adder.add(isA(Integer.class), eq(new Integer(4)) .andReturn(-1); } Thursday, August 29, 13
  13. Internal Methods class Complex { private boolean isSetup = false;

    public String perform() { if (!this.isSetup) { isSetup = this.setup(); } // Seriously hard computations ... } protected boolean setup() { // Lengthy setup involving numerous external classes ... return true; } } • How about mocking/stubbing internal methods? Thursday, August 29, 13
  14. Internal Methods cont. class Complex { private boolean isSetup =

    false; public String perform() { if (!this.isSetup) { isSetup = this.setup(); } // Seriously hard computations ... } protected boolean setup() { // Lengthy setup involving numerous external classes ... return true; } } @Test public void testMethod() { // Mock out the setup method in perform(); Complex complex = new Complex() { @Override protected boolean setup() { return true; } }; complex.perform(); // Note that we test on our partial mock } Right?? • How about mocking internal methods? Thursday, August 29, 13
  15. Internal Methods cont. • How about mocking internal methods? class

    Complex { private boolean isSetup = false; public String perform() { if (!this.isSetup) { isSetup = this.setup(); } // Seriously hard computations ... } protected boolean setup() { // Lengthy setup involving numerous external classes ... return true; } } @Test public void testMethod() { // Mock out the setup method in perform(); Complex complex = new Complex() { @Override protected boolean setup() { return true; } }; complex.perform(); // Note that we test on our partial mock } Thursday, August 29, 13
  16. What’s Wrong?? • Hard to maintain test as code evolves

    • Too tightly coupled with testing class • Forces scope to be protected/public • Partial Mocks are less code too Thursday, August 29, 13
  17. Partial Mocks • Mock internal methods of test class •

    Inherit from testing class • @Override methods • Highly recommended for Groovy • Meta classing issues • Can specify method/constructor params, etc. Thursday, August 29, 13
  18. Partial Mocks Example class Complex() { private boolean isSetup =

    false; public String perform() { if (!this.isSetup) { isSetup = this.setup(); } // Seriously hard computations ... } protected boolean setup() { // Lengthy setup involving numerous external classes ... return true; } } @Test public void testMethod() { // Mock out the setup method in perform(); Complex complex = EasyMock.createMockBuilder(Complex.class) .addMockedMethod(“setup”).createMock(); expect(complex.setup()).andReturn(true); replay(complex); complex.perform(); // Note that we test on our partial mock verify(complex); } Thursday, August 29, 13
  19. Strict Mocks • Advanced mock type (not typical) • Order

    checking on mocks • Fails test if operation sequence deviates • Useful for very specific test types Thursday, August 29, 13
  20. Strict Mocks Example protected final static String INSERT = "INSERT

    INTO searchtarget " + ST_VALUES + " VALUES (?, ?, ?, ?);"; protected void buildQuery(String query, List values) { PreparedCqlQuery<String, String> statement = searchTargetKeyspace.prepareQuery(ST_RESULTS_CF) .withCql(cqlQuery).asPreparedStatement(); for (Object o : values) { if (o instanceof String) { statement.withStringValue((String)o); } else if (o instanceof Integer) { statement.withIntegerValue((Integer)o); } else { statement.withLongValue((Long)o); } } } @Test public void testInsertQuery() { CqlQuery cqlQuery = createMock(CqlQuery.class); PreparedCqlQuery query = createStrictMock(PreparedCqlQuery.class); String queryStr = “testQuery”; expect(keyspace.prepareQuery(isA(ColumnFamily.class))).andReturn(cfQuery); expect(cfQuery.withCql(myQuery)).andReturn(cqlQuery); expect(cqlQuery.asPreparedStatement()).andReturn(query); expect(query.withStringValue("valueFirst")).andReturn(query); expect(query.withIntegerValue(123)).andReturn(query); expect(query.withStringValue("foursquare")).andReturn(query); expect(query.withLongValue(456L)).andReturn(query); EasyMock.replay(cqlQuery, query); new MyTestClass().buildQuery(queryStr, Lists.newArrayList(“valueFirst”, 123, “foursquare”, 456L); EasyMock.verify(cqlQuery, query); } Thursday, August 29, 13
  21. Observing Method Variables • How about checking the actual param

    values passed into the mocked methods? @Test public void testMethod() { // Mock out the setup method in perform(); Connection connection = new Connection() { @Override protected boolean sendResult(Map result) { Assert.assertEquals(5, result.size()); Assert.assertEquals(“Michie”, results.get(“Ken”); ... return true; } }; new MyTest().save(connection); // invokes sendResult() } Right?? Thursday, August 29, 13
  22. • How about checking param values passed into the mocked

    methods? @Test public void testMethod() { // Mock out the setup method in perform(); Connection connection = new Connection() { @Override protected boolean sendResult(Map result) { Assert.assertEquals(5, result.size()); Assert.assertEquals(“Michie”, results.get(“Ken”); ... return true; } }; new MyTest().save(connection); // invokes sendResult() } Observing Method Variables Thursday, August 29, 13
  23. Captures • Mocked call passes a complex Object • Verbose

    constructor, large Map, etc. • Provides better checking than isA(xxx.class), anyXXX() ... • Don’t have to @Override a method call to grab its value (Remember Partial Mocks ex?) Thursday, August 29, 13
  24. Capture Examples import static org.easymock.EasyMock.*; @Test public void testCapture() {

    Connection connection = createMock(Connection.class); // Capturing a Map with many values, too hard to construct Capture<Map<String, String>> myCapture = new Capture<Map<String, String>>(); // Mocks method ‘boolean exchangeState(String, Map); expect(connection.sendResult(EasyMock.capture(myCapture)).andReturn(true); replay(complex); new MyTest().save(connection); // Validate contents of the capture Map<String, String> capturedMap = capture.getValue() Assert.assertEquals(5, capturedMap.size()); Assert.assertEquals(“Michie”, capturedMap.get(“Ken”); ... verify(complex); } Thursday, August 29, 13
  25. Toughies for EasyMock • What about those pesky static methods?

    class DBAggregator() { protected static isJUnit = false; private static DBAggregator myInstance = null; private static List<DBConnections> connections = null; public static synchronized getInstance() { if (myInstance == null) { myInstance = new DBAggregator(); if (!isJUnit) { connections = Connections.setupStaticDBConnections(); } } return myInstance; } } Right?? Thursday, August 29, 13
  26. Toughies for EasyMock • What about those pesky static methods?

    class DBAggregator() { protected static isJUnit = false; private static DBAggregator myInstance = null; private static List<DBConnections> connections = null; public static synchronized getInstance() { if (myInstance == null) { myInstance = new DBAggregator(); if (!isJUnit) { connections = Connections.setupStaticDBConnections(); } } return myInstance; } } Thursday, August 29, 13
  27. PowerMock • Solution to those tricky ones in EasyMock •

    Static methods/initializers • Constructors • Final classes and methods • Private methods • PLUS it integrates seamlessly into EasyMock! Thursday, August 29, 13
  28. PowerMock Example class DBAggregator() { private static DBAggregator myInstance =

    null; private static List<DBConnections> connections = null; public static synchronized getInstance() { if (myInstance == null) { myInstance = new DBAggregator(); connections = Connections.setupStaticDBConnections(); } return myInstance; } } @RunWith(PowerMockRunner.class) @PrepareForTest(Connections.class) public class DBAggregatorTest { @Test public void testGetInstance() { List<DBConnections> conns = new ArrayList<DBConnections>(); mockStatic(Connections.class); expect(Connections.setupStaticDBConnections).andReturn(conns); PowerMock.replay(Connections.class); DBAggregator.getInstance(); PowerMock.verify(Connections.class); } } Thursday, August 29, 13
  29. Tips and Tricks • Spend just 1 extra hour writing

    tests • Saves you time later! Promise! • Consolidate common setup methods • @Before is a nice place for Mocks/excepts • You can reset mocks in EasyMock Thursday, August 29, 13
  30. Tips and Tricks public class MyTest { public void replayAll(Object

    ... objs) { for (Object o : objs) { EasyMock.replay(o); } EasyMock.replay(commonMock1, ...); PowerMock.replayAll(); } public void verifyAll(Object ... objs) { for (Object o : objs) { EasyMock.verify(o); } EasyMock.verify(commonMock1, ...); PowerMock.verifyAll(); } ... } • PowerMock conveniently already has replayAll and verifyAll(Object... objs) Thursday, August 29, 13
  31. Links, etc. • EasyMock & PowerMock • http://easymock.org/ EasyMock3_1_Documentation.html •

    https://code.google.com/p/powermock/ • Gradle testCompile 'junit:junit:4.11' testCompile 'org.easymock:easymock:3.1' testCompile 'org.powermock:powermock-easymock-release-full:1.4.10' Thursday, August 29, 13