All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scalatest.mock.EasyMockSugar.scala Maven / Gradle / Ivy

There is a newer version: 2.0.M6-SNAP27
Show newest version
/*
 * Copyright 2001-2009 Artima, Inc.
 *
 * Licensed 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.
 */
package org.scalatest.mock

import org.scalatest._
import org.easymock.IExpectationSetters
import org.easymock.EasyMock
import org.easymock.EasyMock.{expect => easyMockExpect, expectLastCall}
import scala.reflect.Manifest

/**
 * Trait that provides some basic syntax sugar for EasyMock.
 *
 * 

* Using the EasyMock API directly, you create a mock with: *

* *
 * val mockCollaborator = createMock(classOf[Collaborator])
 * 
* *

* With this trait, you can shorten that to: *

* *
 * val mockCollaborator = mock[Collaborator]
 * 
* *

* After creating mocks, you set expectations on them, using syntax like this: *

* *
 * mockCollaborator.documentAdded("Document")
 * mockCollaborator.documentChanged("Document")
 * expectLastCall().times(3)
 * 
* *

* If you wish to highlight which statements are setting expectations on the mock (versus * which ones are actually using the mock), you can place them in an expecting * clause, provided by this trait, like this: *

* *
 * expecting {
 *   mockCollaborator.documentAdded("Document")
 *   mockCollaborator.documentChanged("Document")
 *   lastCall.times(3)
 * }
 * 
* *

* Using an expecting clause is optional, because it does nothing but visually indicate * which statements are setting expectations on mocks. (Note: this trait also provides the lastCall * method, which just calls expectLastCall.) *

* *

* Once you've set expectations on the mock objects, you must invoke replay on * the mocks to indicate you are done setting expectations, and will start using the mock. * After using the mock, you must invoke verify to check to make sure the mock * was used in accordance with the expectations you set on it. Here's how that looks when you * use the EasyMock API directly: *

* *
 * replay(mockCollaborator)
 * classUnderTest.addDocument("Document", new Array[Byte](0))
 * classUnderTest.addDocument("Document", new Array[Byte](0))
 * classUnderTest.addDocument("Document", new Array[Byte](0))
 * classUnderTest.addDocument("Document", new Array[Byte](0))
 * verify(mockCollaborator)
 * 
* *

* This trait enables you to use the following, more declarative syntax instead: *

* *
 * whenExecuting(mockCollaborator) {
 *   classUnderTest.addDocument("Document", new Array[Byte](0))
 *   classUnderTest.addDocument("Document", new Array[Byte](0))
 *   classUnderTest.addDocument("Document", new Array[Byte](0))
 *   classUnderTest.addDocument("Document", new Array[Byte](0))
 * }
 * 
* *

* The whenExecuting method will pass the mockCollaborator to * replay, execute the passed function (your code that uses the mock), and * call verify, passing in the mockCollaborator. If you want to * use multiple mocks, you can pass multiple mocks to whenExecuting. *

* *

* To summarize, here's what a typical test using EasyMockSugar looks like: *

* *
 * val mockCollaborator = mock[Collaborator]
 *
 * expecting {
 *   mockCollaborator.documentAdded("Document")
 *   mockCollaborator.documentChanged("Document")
 *   lastCall.times(3)
 * }
 *
 * whenExecuting(mockCollaborator) {
 *   classUnderTest.addDocument("Document", new Array[Byte](0))
 *   classUnderTest.addDocument("Document", new Array[Byte](0))
 *   classUnderTest.addDocument("Document", new Array[Byte](0))
 *   classUnderTest.addDocument("Document", new Array[Byte](0))
 * }
 * 
* *

* An alternative approach is to place your mock objects in a MockObjects holder object referenced * from an implicit val, then use the overloaded variant of whenExecuting that * takes an implicit MockObjects parameter. Here's how that would look: *

* *
 * implicit val mocks = MockObjects(mock[Collaborator])
 *
 * expecting {
 *   mockCollaborator.documentAdded("Document")
 *   mockCollaborator.documentChanged("Document")
 *   lastCall.times(3)
 * }
 *
 * whenExecuting {
 *   classUnderTest.addDocument("Document", new Array[Byte](0))
 *   classUnderTest.addDocument("Document", new Array[Byte](0))
 *   classUnderTest.addDocument("Document", new Array[Byte](0))
 *   classUnderTest.addDocument("Document", new Array[Byte](0))
 * }
 * 
* *

* Note: As of ScalaTest 1.3, this trait supports EasyMock 3, with no dependencies on EasyMock class extension. *

* * @author Bill Venners * @author George Berger */ trait EasyMockSugar { /** * Implicit conversion that invokes the expect method on the EasyMock companion object (i.e., the * static expect method in Java class org.easymock.EasyMock). * *

* In a ScalaTest Suite, the expect method defined in Assertions, and inherited by Suite, * interferes with the expect method if imported from EasyMock. You can invoke it by qualifying it, i.e., * EasyMock.expect, or by changing its name on import, like this: * *

   * import org.easymock.EasyMock.{expect => easyMockExpect, _}
   * 
* *

* But if you mix in this trait, you can just invoke call instead. *

* *

* You can use this method, for example, to chain expectations like this: *

* *
   * expecting {
   *   call(mock.getName).andReturn("Ben Franklin")
   * }
   * 
* *

* Note: the name of this methods is call, not expectCall because * "expect" appears in the surrounding expecting clause provided by this trait. *

* *

* Moreover, because this method is marked implicit, you will usually be able to simply * leave it off. So long as the result of the method call you are expecting doesn't have * a method that satisfies the subsequent invocation (such as andReturn in this * example), the Scala compiler will invoke call for you * implicitly. Here's how that looks: *

* *
   * expecting {
   *   mock.getName.andReturn("Ben Franklin")
   * }
   * 
* * @param value - the result of invoking a method on mock prior to invoking replay. */ implicit def call[T](value: T): IExpectationSetters[T] = easyMockExpect(value) /** * Invokes the expectLastCall method on the EasyMock companion object (i.e., the * static expect method in Java class org.easymock.EasyMock). * *

* This method is provided simply to allow you to avoid repeating "expect" inside an * expecting clause. Here's an example that uses the expectLastCall directly * to express the expectation that the getName method will be invoked three times * on a mock, each time returning "Ben Franklin": *

* *
   * expecting {
   *   mock.getName.andReturn("Ben Franklin")
   *   expectLastCall.times(3)
   * }
   * 
* *

* Using this method, you can compress this to: *

* *
   * expecting {
   *   mock.getName.andReturn("Ben Franklin")
   *   lastCall.times(3)
   * }
   * 
*/ def lastCall[T]: IExpectationSetters[T] = expectLastCall() /** * Invokes the createMock method on the EasyMock companion object (i.e., the * static createMock method in Java class org.easymock.classextension.EasyMock). * *

* Using the EasyMock API directly, you create a mock with: *

* *
   * val mockCollaborator = createMock(classOf[Collaborator])
   * 
* *

* Using this method, you can shorten that to: *

* *
   * val mockCollaborator = mock[Collaborator]
   * 
*/ def mock[T <: AnyRef](implicit manifest: Manifest[T]): T = { EasyMock.createMock(manifest.erasure.asInstanceOf[Class[T]]) } /** * Invokes the createStrictMock method on the EasyMock companion object (i.e., the * static createStrictMock method in Java class org.easymock.classextension.EasyMock). * *

* Using the EasyMock API directly, you create a strict mock with: *

* *
   * val mockCollaborator = createStrictMock(classOf[Collaborator])
   * 
* *

* Using this trait, you can shorten that to: *

* *
   * val mockCollaborator = strictMock[Collaborator]
   * 
*/ def strictMock[T <: AnyRef](implicit manifest: Manifest[T]): T = { EasyMock.createStrictMock(manifest.erasure.asInstanceOf[Class[T]]) } /** * Invokes the createNiceMock method on the EasyMock companion object (i.e., the * static createNiceMock method in Java class org.easymock.classextension.EasyMock). * *

* Using the EasyMock API directly, you create a nice mock with: *

* *
   * val mockCollaborator = createNiceMock(classOf[Collaborator])
   * 
* *

* Using this trait, you can shorten that to: *

* *
   * val mockCollaborator = niceMock[Collaborator]
   * 
*/ def niceMock[T <: AnyRef](implicit manifest: Manifest[T]): T = { EasyMock.createNiceMock(manifest.erasure.asInstanceOf[Class[T]]) } /** * Provides a visual clue to readers of the code that a set of statements are expectations being * set on mocks. * *

* Using the EasyMock API directly, you set expectations on a mock object with syntax like: *

* *
   * mockCollaborator.documentAdded("Document")
   * mockCollaborator.documentChanged("Document")
   * expectLastCall().times(3)
   * 
* *

* This expecting method can make it more obvious which portion of your test code * is devoted to setting expectations on mock objects. For example: *

* *
   * expecting {
   *   mockCollaborator.documentAdded("Document")
   *   mockCollaborator.documentChanged("Document")
   *   lastCall.times(3)
   * }
   * 
* *

* Using an expecting clause is optional, because it does nothing besides visually indicate * which statements are setting expectations on mocks. Note: this trait also provides the lastCall * method, which just calls expectLastCall. This allows you to avoid writing "expect" twice. * Also, the reason expecting doesn't take a by-name parameter, execute that, then call * replay is because you would then need to pass your mock object or objects into * expecting. Since you already need to pass the mocks into whenExecuting so * that verify can be invoked on them, it yields more concise client code to have * whenExecuting invoke replay on the mocks first rather than having * expecting invoke replay last. *

*/ def expecting(unused: Any) = () /** * Invokes replay on the passed mock object or objects, executes the passed function, then invokes * verify on the passed mock object or objects. * *

* Once you've set expectations on some mock objects, you must invoke replay on * the mocks to indicate you are done setting expectations, and will start using the mocks. * After using the mocks, you must invoke verify to check to make sure the mocks * were used in accordance with the expectations you set on it. Here's how that looks when you * use the EasyMock API directly: *

* * *
   * replay(mock)
   * classUnderTest.addDocument("Document", new Array[Byte](0))
   * classUnderTest.addDocument("Document", new Array[Byte](0))
   * classUnderTest.addDocument("Document", new Array[Byte](0))
   * classUnderTest.addDocument("Document", new Array[Byte](0))
   * verify(mock)
   * 
* *

* This method enables you to use the following, more declarative syntax instead: *

* *
   * whenExecuting(mockCollaborator) {
   *   classUnderTest.addDocument("Document", new Array[Byte](0))
   *   classUnderTest.addDocument("Document", new Array[Byte](0))
   *   classUnderTest.addDocument("Document", new Array[Byte](0))
   *   classUnderTest.addDocument("Document", new Array[Byte](0))
   * }
   * 
* *

* If you are working with multiple mock objects at once, you simply pass * them all to whenExecuting, like this: *

* *
   * whenExecuting(mock1, mock2, mock3) {
   *   // ...
   * }
   * 
* *

* The whenExecuting method will first invoke EasyMock.reply * once for each mock you supplied, execute the passed function, then * invoke EasyMock.verify once for each mock you supplied. If an exception * is thrown by the passed function, whenExecuting will complete abruptly with * that same exception without executing verify on any of the mocks. *

* * @param mocks one or more mock objects to invoke replay before using and verify after using. * @throws IllegalArgumentException if no mocks are passed */ def whenExecuting(mocks: AnyRef*)(fun: => Unit) = { require(mocks.length > 0, "Must pass at least one mock to whenExecuting, but mocks.length was 0.") for (m <- mocks) EasyMock.replay(m) fun // Don't put this in a try block, so that if fun throws an exception // it propagates out immediately and shows up as the cause of the failed test for (m <- mocks) EasyMock.verify(m) } /** * Holder class for a collection of mocks that can be passed implicitly to one form of the * overloaded whenExecuting method. * * @param mocks one or more mock objects that you intend to pass to whenExecuting * @throws IllegalArgumentException if no mocks are passed */ case class MockObjects(mocks: AnyRef*) { require(mocks.length > 0, "Must pass at least one mock to MockObjects constructor, but mocks.length was 0.") } /** * Invokes replay on the mock object or objects passed via an implicit parameter, * executes the passed function, then invokes verify on the passed mock object or objects. * *

* Once you've set expectations on some mock objects, you must invoke replay on * the mocks to indicate you are done setting expectations, and will start using the mocks. * After using the mocks, you must invoke verify to check to make sure the mocks * were used in accordance with the expectations you set on it. Here's how that looks when you * use the EasyMock API directly: *

* * *
   * replay(mock)
   * classUnderTest.addDocument("Document", new Array[Byte](0))
   * classUnderTest.addDocument("Document", new Array[Byte](0))
   * classUnderTest.addDocument("Document", new Array[Byte](0))
   * classUnderTest.addDocument("Document", new Array[Byte](0))
   * verify(mock)
   * 
* *

* This method enables you to use the following, more declarative syntax instead: *

* *
   * implicit val mocks = MockObjects(mockCollaborator)
   *
   * whenExecuting {
   *   classUnderTest.addDocument("Document", new Array[Byte](0))
   *   classUnderTest.addDocument("Document", new Array[Byte](0))
   *   classUnderTest.addDocument("Document", new Array[Byte](0))
   *   classUnderTest.addDocument("Document", new Array[Byte](0))
   * }
   * 
* *

* If you are working with multiple mock objects at once, you simply pass * them all to MockObjects, like this: *

* *
   * implicit val mocks = MockObjects(mock1, mock2, mock3)
   * 
* *

* The whenExecuting method will first invoke EasyMock.reply * once for each mock you supplied, execute the passed function, then * invoke EasyMock.verify once for each mock you supplied. If an exception * is thrown by the passed function, whenExecuting will complete abruptly with * that same exception without executing verify on any of the mocks. *

*/ def whenExecuting(fun: => Unit)(implicit mocks: MockObjects) { whenExecuting(mocks.mocks: _*)(fun) } } /** * Companion object that facilitates the importing of EasyMockSugar members as * an alternative to mixing it in. One use case is to import EasyMockSugar members so you can use * them in the Scala interpreter. */ // TODO: Fill in an example object EasyMockSugar extends EasyMockSugar




© 2015 - 2024 Weber Informatics LLC | Privacy Policy