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

org.specs2.mock.mockito.MocksCreation.scala Maven / Gradle / Ivy

There is a newer version: 3.7
Show newest version
package org.specs2
package mock
package mockito

import control.Property
import reflect.ClassesOf
import org.mockito.invocation._
import scala.reflect.ClassTag
import org.mockito.internal.debugging.VerboseMockInvocationLogger

/**
 * This trait provides methods to create mocks and spies.
 */
trait MocksCreation extends TheMockitoMocker with ClassesOf {
  /**
   * create a mock object: val m = mock[java.util.List[String]]
   */
  def mock[T : ClassTag]: T = mocker.mock(implicitly[ClassTag[T]])
  /**
   * create a mock object with a name: val m = mockAs[java.util.List[String]]("name")
   */
  def mockAs[T : ClassTag](name: String): T = Mocked[T]().as(name)
  /**
   * create a mock object with some specific settings: val m = mock[java.util.List[String]](settings)
   */
  def mock[T : ClassTag](settings: org.mockito.MockSettings): T = Mocked[T](settings).done
  /**
   * implicit allowing to define the mock settings with a nice syntax:
   *  - named mock: val m = mock[java.util.List[String]].as("name")
   *  - smart mock: val m = mock[java.util.List[String]].smart
   *  - other settings: val m = mock[java.util.List[String]].
   *         settings(name = "list",
   *                  defaultReturn = 10,
   *                  extraInterfaces = classesOf[Cloneable, Serializable])
   */
  implicit def mocked[T : ClassTag](t: =>T) = Mocked[T]()

  /** support class to create a mock object with specific settings */
  private[specs2]
  case class Mocked[T : ClassTag](mockitoSettings: org.mockito.MockSettings = org.mockito.Mockito.withSettings) {
    def as(n: String) = settings(name = n)
    def verbose = Mocked[T](mockitoSettings.invocationListeners(new VerboseMockInvocationLogger())).done
    def smart = Mocked[T](mockitoSettings.defaultAnswer(org.mockito.Mockito.RETURNS_SMART_NULLS)).done
    def defaultReturn(a: Any) = settings(defaultReturn = a)
    def defaultAnswer[S](answer: InvocationOnMock => S) = settings(defaultAnswer = (i: InvocationOnMock) => answer(i): Any)
    def extraInterface[T : ClassTag] = settings(extraInterface = implicitly[ClassTag[T]].runtimeClass)
    def extraInterfaces[T1 : ClassTag, T2: ClassTag] = settings(extraInterfaces = classesOf[T1, T2])
    def extraInterfaces[T1 : ClassTag, T2: ClassTag, T3: ClassTag] = settings(extraInterfaces = classesOf[T1, T2, T3])
    def extraInterfaces[T1 : ClassTag, T2: ClassTag, T3: ClassTag, T4: ClassTag] = settings(extraInterfaces = classesOf[T1, T2, T3, T4])

    def settings(name            : MockProperty[String] = MockProperty[String](),
                 smart           : MockProperty[Boolean] = MockProperty[Boolean](),
                 verbose         : MockProperty[Boolean] = MockProperty[Boolean](),
                 defaultAnswer   : MockProperty[InvocationOnMock => Any] = MockProperty[InvocationOnMock => Any](),
                 defaultReturn   : MockProperty[Any] = MockProperty[Any](),
                 extraInterface  : MockProperty[Class[_]] = MockProperty[Class[_]](),
                 extraInterfaces : MockProperty[Seq[Class[_]]] = MockProperty[Seq[Class[_]]]()) = {
      update(name)(n => mockitoSettings.name(n)).
      update(smart)(s => if (s) mockitoSettings.defaultAnswer(org.mockito.Mockito.RETURNS_SMART_NULLS) else mockitoSettings).
      update(verbose)(v => if (v) mockitoSettings.invocationListeners(new VerboseMockInvocationLogger()) else mockitoSettings).
      update(defaultAnswer)(a => mockitoSettings.defaultAnswer(mocker.answer(a))).
      update(defaultReturn)(r => mockitoSettings.defaultAnswer(mocker.answer(r))).
      update(extraInterface)(i => mockitoSettings.extraInterfaces(i)).
      update(extraInterfaces)(i => mockitoSettings.extraInterfaces(i:_*)).done
    }
    /**
     * @return the mock object
     */
    def done: T = mocker.mock[T](mockitoSettings)

    /** update the settings with a new setting value if available */
    private def update[P](prop: MockProperty[P])(f: P => org.mockito.MockSettings) = prop.toOption.map(p => Mocked[T](f(p))).getOrElse(this)
  }

  /**
   * this implicit helps with defining optional values for mockito settings
   */
  implicit def anyToMockProperty[T](t: =>T): MockProperty[T] = MockProperty(Property(t))
  case class MockProperty[T](p: Property[T] = Property[T]()) {
    def toOption: Option[T] = p.toOption
  }

  /**
   * create a mock object with smart return values: val m = smartMock[java.util.List[String]]
   * 
   * This is the equivalent of Mockito.mock(List.class, SMART_NULLVALUES) but testing shows that it is not working well with Scala.
   */
  def smartMock[T : ClassTag]: T = Mocked[T]().smart
  /**
   * create a spy on an object. 
   * 
   * A spy is a real object but can still have some of its methods stubbed. However the syntax for stubbing a spy is a bit different than 
   * with a mock:
   * {{{
   * val s = spy(new LinkedList[String])
   * doReturn("one").when(s).get(0) // instead of s.get(0) returns "one" which would throw an exception
   * 
   * }}}
   */
  def spy[T](m: T): T = mocker.spy(m)
  /**
   * ignore stubbed methods when verifying that a mock has no more interactions
   */
  def ignoreStubs(mocks: AnyRef*): IgnoreStubs = IgnoreStubs(mocker.ignoreStubs(mocks:_*))
}

/**
 * This class encapsulate mocks which must have their stubbed methods ignored in verification methods
 */
case class IgnoreStubs(mocks: Seq[AnyRef])




© 2015 - 2024 Weber Informatics LLC | Privacy Policy