diff --git a/common/src/main/scala-2/org/mockito/MockCreator.scala b/common/src/main/scala-2/org/mockito/MockCreator.scala
new file mode 100644
index 00000000..bb18658b
--- /dev/null
+++ b/common/src/main/scala-2/org/mockito/MockCreator.scala
@@ -0,0 +1,81 @@
+package org.mockito
+
+import org.mockito.internal.handler.ScalaMockHandler
+import org.mockito.invocation.MockHandler
+import org.mockito.mock.MockCreationSettings
+import org.mockito.quality.Strictness
+import org.mockito.stubbing.{ Answer, CallsRealMethods, DefaultAnswer }
+import org.scalactic.Prettifier
+
+import scala.reflect.ClassTag
+import scala.reflect.runtime.universe.WeakTypeTag
+
+private[mockito] trait MockCreator extends MockCreatorRuntime {
+
+ /**
+ * Delegates to Mockito.mock(type: Class[T]) It provides a nicer API as you can, for instance, do mock[MyClass] instead of
+ * mock(classOf[MyClass])
+ *
+ * It also pre-stub the mock so the compiler-generated methods that provide the values for the default arguments are called, ie: given def
+ * iHaveSomeDefaultArguments(noDefault: String, default: String = "default value")
+ *
+ * without this fix, if you call it as iHaveSomeDefaultArguments("I'm not gonna pass the second argument") then you could have not verified it like
+ * verify(aMock).iHaveSomeDefaultArguments("I'm not gonna pass the second argument", "default value") as the value for the second parameter would have been null...
+ */
+ def mock[T <: AnyRef: ClassTag: WeakTypeTag](implicit defaultAnswer: DefaultAnswer, $pt: Prettifier): T =
+ mock[T](defaultAnswer)
+
+ def mock[T <: AnyRef: ClassTag: WeakTypeTag](defaultAnswer: Answer[?])(implicit $pt: Prettifier): T =
+ mock[T](DefaultAnswer(defaultAnswer))
+
+ /**
+ * Delegates to Mockito.mock(type: Class[T], defaultAnswer: Answer[_]) It provides a nicer API as you can, for instance, do mock[MyClass](defaultAnswer)
+ * instead of mock(classOf[MyClass], defaultAnswer)
+ *
+ * It also pre-stub the mock so the compiler-generated methods that provide the values for the default arguments are called, ie: given def
+ * iHaveSomeDefaultArguments(noDefault: String, default: String = "default value")
+ *
+ * without this fix, if you call it as iHaveSomeDefaultArguments("I'm not gonna pass the second argument") then you could have not verified it like
+ * verify(aMock).iHaveSomeDefaultArguments("I'm not gonna pass the second argument", "default value") as the value for the second parameter would have been null...
+ */
+ def mock[T <: AnyRef: ClassTag: WeakTypeTag](defaultAnswer: DefaultAnswer)(implicit $pt: Prettifier): T =
+ mock[T](withSettings(defaultAnswer))
+
+ /**
+ * Delegates to Mockito.mock(type: Class[T], mockSettings: MockSettings) It provides a nicer API as you can, for instance, do
+ * mock[MyClass](mockSettings) instead of mock(classOf[MyClass], mockSettings)
+ *
+ * It also pre-stub the mock so the compiler-generated methods that provide the values for the default arguments are called, ie: given def
+ * iHaveSomeDefaultArguments(noDefault: String, default: String = "default value")
+ *
+ * without this fix, if you call it as iHaveSomeDefaultArguments("I'm not gonna pass the second argument") then you could have not verified it like
+ * verify(aMock).iHaveSomeDefaultArguments("I'm not gonna pass the second argument", "default value") as the value for the second parameter would have been null...
+ */
+ def mock[T <: AnyRef: ClassTag: WeakTypeTag](mockSettings: MockSettings)(implicit $pt: Prettifier): T =
+ createMock(mockSettings)
+
+ /**
+ * Delegates to Mockito.mock(type: Class[T], name: String) It provides a nicer API as you can, for instance, do mock[MyClass](name) instead of
+ * mock(classOf[MyClass], name)
+ *
+ * It also pre-stub the mock so the compiler-generated methods that provide the values for the default arguments are called, ie: given def
+ * iHaveSomeDefaultArguments(noDefault: String, default: String = "default value")
+ *
+ * without this fix, if you call it as iHaveSomeDefaultArguments("I'm not gonna pass the second argument") then you could have not verified it like
+ * verify(aMock).iHaveSomeDefaultArguments("I'm not gonna pass the second argument", "default value") as the value for the second parameter would have been null...
+ */
+ def mock[T <: AnyRef: ClassTag: WeakTypeTag](name: String)(implicit defaultAnswer: DefaultAnswer, $pt: Prettifier): T =
+ mock(withSettings.name(name))
+
+ def spy[T <: AnyRef: ClassTag: WeakTypeTag](realObj: T, lenient: Boolean = false)(implicit $pt: Prettifier): T = {
+ val mockSettings: MockSettings = withSettings(CallsRealMethods).spiedInstance(realObj)
+ val settings = if (lenient) mockSettings.strictness(Strictness.LENIENT) else mockSettings
+ mock[T](settings)
+ }
+
+ private[mockito] def createMock[T <: AnyRef: ClassTag: WeakTypeTag](
+ mockSettings: MockSettings,
+ mockHandler: (MockCreationSettings[T], Prettifier) => MockHandler[T] = (settings: MockCreationSettings[T], pt: Prettifier) => ScalaMockHandler(settings)(pt)
+ )(implicit $pt: Prettifier): T =
+ createMock[T](mockSettings, ReflectionUtils.extraInterfaces[T], mockHandler)
+}
diff --git a/common/src/main/scala-2/org/mockito/MockitoEnhancer.scala b/common/src/main/scala-2/org/mockito/MockitoEnhancer.scala
new file mode 100644
index 00000000..4c989c55
--- /dev/null
+++ b/common/src/main/scala-2/org/mockito/MockitoEnhancer.scala
@@ -0,0 +1,9 @@
+package org.mockito
+
+/**
+ * Scala 2 specific trait that provides object mocking functionality. Extends MockCreator (Scala 2 version with WeakTypeTag) and MockitoEnhancerRuntime (shared utilities including
+ * withObject methods).
+ *
+ * This is a thin compatibility layer - all actual functionality is in MockCreator and MockitoEnhancerRuntime.
+ */
+private[mockito] trait MockitoEnhancer extends MockCreator with MockitoEnhancerRuntime
diff --git a/common/src/main/scala/org/mockito/ReflectionUtils.scala b/common/src/main/scala-2/org/mockito/ReflectionUtils.scala
similarity index 100%
rename from common/src/main/scala/org/mockito/ReflectionUtils.scala
rename to common/src/main/scala-2/org/mockito/ReflectionUtils.scala
diff --git a/common/src/main/scala/org/mockito/MockitoAPI.scala b/common/src/main/scala/org/mockito/MockitoAPI.scala
index d4105ab9..c43175bd 100644
--- a/common/src/main/scala/org/mockito/MockitoAPI.scala
+++ b/common/src/main/scala/org/mockito/MockitoAPI.scala
@@ -21,7 +21,7 @@ import org.mockito.internal.stubbing.answers.ScalaThrowsException
import org.mockito.internal.util.MockUtil
import org.mockito.internal.util.reflection.LenientCopyTool
import org.mockito.internal.{ ValueClassExtractor, ValueClassWrapper }
-import org.mockito.invocation.{ Invocation, InvocationContainer, InvocationOnMock, MockHandler }
+import org.mockito.invocation.{ InvocationOnMock, MockHandler }
import org.mockito.mock.MockCreationSettings
import org.mockito.quality.Strictness
import org.mockito.stubbing.*
@@ -30,29 +30,59 @@ import org.scalactic.{ Equality, Prettifier }
import scala.jdk.CollectionConverters.*
import scala.reflect.ClassTag
-import scala.reflect.runtime.universe.WeakTypeTag
private[mockito] trait ScalacticSerialisableHack {
// Hack until Equality can be made serialisable
implicit def mockitoSerialisableEquality[T]: Equality[T] = serialisableEquality[T]
}
-private[mockito] trait MockCreator {
- def mock[T <: AnyRef: ClassTag: WeakTypeTag](implicit defaultAnswer: DefaultAnswer, $pt: Prettifier): T
- def mock[T <: AnyRef: ClassTag: WeakTypeTag](defaultAnswer: Answer[?])(implicit $pt: Prettifier): T =
- mock[T](DefaultAnswer(defaultAnswer))
- def mock[T <: AnyRef: ClassTag: WeakTypeTag](defaultAnswer: DefaultAnswer)(implicit $pt: Prettifier): T
- def mock[T <: AnyRef: ClassTag: WeakTypeTag](mockSettings: MockSettings)(implicit $pt: Prettifier): T
- def mock[T <: AnyRef: ClassTag: WeakTypeTag](name: String)(implicit defaultAnswer: DefaultAnswer, $pt: Prettifier): T
-
- def spy[T <: AnyRef: ClassTag: WeakTypeTag](realObj: T, lenient: Boolean)(implicit $pt: Prettifier): T
- def spyLambda[T <: AnyRef: ClassTag](realObj: T): T
+/**
+ * Runtime support for MockCreator. Provides createMock implementation using only ClassTag (Scala 3 compatible). Shared across Scala 2 and Scala 3. Version-specific MockCreator
+ * traits extend this.
+ */
+private[mockito] trait MockCreatorRuntime {
/**
* Delegates to Mockito.withSettings(), it's only here to expose the full Mockito API
*/
def withSettings(implicit defaultAnswer: DefaultAnswer): MockSettings =
Mockito.withSettings().defaultAnswer(defaultAnswer)
+
+ private[mockito] def createMock[T <: AnyRef: ClassTag](
+ mockSettings: MockSettings,
+ interfaces: List[Class[?]],
+ mockHandler: (MockCreationSettings[T], Prettifier) => MockHandler[T]
+ )(implicit $pt: Prettifier): T = {
+ val realClass: Class[T] = mockSettings match {
+ case m: MockSettingsImpl[?] if !m.getExtraInterfaces.isEmpty =>
+ throw new IllegalArgumentException("If you want to add extra traits to the mock use the syntax mock[MyClass with MyTrait]")
+ case m: MockSettingsImpl[?] if m.getSpiedInstance != null => m.getSpiedInstance.getClass.asInstanceOf[Class[T]]
+ case _ => clazz
+ }
+
+ val settings =
+ if (interfaces.nonEmpty) mockSettings.extraInterfaces(interfaces*)
+ else mockSettings
+
+ def createMock(settings: MockCreationSettings[T]): T = {
+ val mock = getMockMaker.createMock(settings, mockHandler(settings, $pt))
+ val spiedInstance = settings.getSpiedInstance
+ if (spiedInstance != null) new LenientCopyTool().copyToMock(spiedInstance, mock)
+ mock
+ }
+
+ settings match {
+ case s: MockSettingsImpl[?] =>
+ val creationSettings = s.build[T](realClass)
+ val mock = createMock(creationSettings)
+ mockingProgress.mockingStarted(mock, creationSettings)
+ mock
+ case _ =>
+ throw new IllegalArgumentException(s"""Unexpected implementation of '${settings.getClass.getCanonicalName}'
+ |At the moment, you cannot provide your own implementations of that class.""".stripMargin)
+ }
+ }
+
}
//noinspection MutatorLikeMethodIsParameterless
@@ -451,101 +481,10 @@ private[mockito] trait DoSomething {
// }
}
-private[mockito] trait MockitoEnhancer extends MockCreator {
-
- /**
- * Delegates to Mockito.mock(type: Class[T]) It provides a nicer API as you can, for instance, do mock[MyClass] instead of
- * mock(classOf[MyClass])
- *
- * It also pre-stub the mock so the compiler-generated methods that provide the values for the default arguments are called, ie: given def
- * iHaveSomeDefaultArguments(noDefault: String, default: String = "default value")
- *
- * without this fix, if you call it as iHaveSomeDefaultArguments("I'm not gonna pass the second argument") then you could have not verified it like
- * verify(aMock).iHaveSomeDefaultArguments("I'm not gonna pass the second argument", "default value") as the value for the second parameter would have been null...
- */
- override def mock[T <: AnyRef: ClassTag: WeakTypeTag](implicit defaultAnswer: DefaultAnswer, $pt: Prettifier): T =
- createMock(withSettings)
-
- /**
- * Delegates to Mockito.mock(type: Class[T], defaultAnswer: Answer[_]) It provides a nicer API as you can, for instance, do mock[MyClass](defaultAnswer)
- * instead of mock(classOf[MyClass], defaultAnswer)
- *
- * It also pre-stub the mock so the compiler-generated methods that provide the values for the default arguments are called, ie: given def
- * iHaveSomeDefaultArguments(noDefault: String, default: String = "default value")
- *
- * without this fix, if you call it as iHaveSomeDefaultArguments("I'm not gonna pass the second argument") then you could have not verified it like
- * verify(aMock).iHaveSomeDefaultArguments("I'm not gonna pass the second argument", "default value") as the value for the second parameter would have been null...
- */
- override def mock[T <: AnyRef: ClassTag: WeakTypeTag](defaultAnswer: DefaultAnswer)(implicit $pt: Prettifier): T =
- createMock(withSettings(defaultAnswer))
-
- /**
- * Delegates to Mockito.mock(type: Class[T], mockSettings: MockSettings) It provides a nicer API as you can, for instance, do
- * mock[MyClass](mockSettings) instead of mock(classOf[MyClass], mockSettings)
- *
- * It also pre-stub the mock so the compiler-generated methods that provide the values for the default arguments are called, ie: given def
- * iHaveSomeDefaultArguments(noDefault: String, default: String = "default value")
- *
- * without this fix, if you call it as iHaveSomeDefaultArguments("I'm not gonna pass the second argument") then you could have not verified it like
- * verify(aMock).iHaveSomeDefaultArguments("I'm not gonna pass the second argument", "default value") as the value for the second parameter would have been null...
- */
- override def mock[T <: AnyRef: ClassTag: WeakTypeTag](mockSettings: MockSettings)(implicit $pt: Prettifier): T =
- createMock(mockSettings)
-
- private def createMock[T <: AnyRef: ClassTag: WeakTypeTag](
- mockSettings: MockSettings,
- mockHandler: (MockCreationSettings[T], Prettifier) => MockHandler[T] = (settings: MockCreationSettings[T], pt: Prettifier) => ScalaMockHandler(settings)(pt)
- )(implicit $pt: Prettifier): T = {
- val interfaces = ReflectionUtils.extraInterfaces
-
- val realClass: Class[T] = mockSettings match {
- case m: MockSettingsImpl[?] if !m.getExtraInterfaces.isEmpty =>
- throw new IllegalArgumentException("If you want to add extra traits to the mock use the syntax mock[MyClass with MyTrait]")
- case m: MockSettingsImpl[?] if m.getSpiedInstance != null => m.getSpiedInstance.getClass.asInstanceOf[Class[T]]
- case _ => clazz
- }
-
- val settings =
- if (interfaces.nonEmpty) mockSettings.extraInterfaces(interfaces*)
- else mockSettings
-
- def createMock(settings: MockCreationSettings[T]): T = {
- val mock = getMockMaker.createMock(settings, mockHandler(settings, $pt))
- val spiedInstance = settings.getSpiedInstance
- if (spiedInstance != null) new LenientCopyTool().copyToMock(spiedInstance, mock)
- mock
- }
-
- settings match {
- case s: MockSettingsImpl[?] =>
- val creationSettings = s.build[T](realClass)
- val mock = createMock(creationSettings)
- mockingProgress.mockingStarted(mock, creationSettings)
- mock
- case _ =>
- throw new IllegalArgumentException(s"""Unexpected implementation of '${settings.getClass.getCanonicalName}'
- |At the moment, you cannot provide your own implementations of that class.""".stripMargin)
- }
- }
-
- /**
- * Delegates to Mockito.mock(type: Class[T], name: String) It provides a nicer API as you can, for instance, do mock[MyClass](name) instead of
- * mock(classOf[MyClass], name)
- *
- * It also pre-stub the mock so the compiler-generated methods that provide the values for the default arguments are called, ie: given def
- * iHaveSomeDefaultArguments(noDefault: String, default: String = "default value")
- *
- * without this fix, if you call it as iHaveSomeDefaultArguments("I'm not gonna pass the second argument") then you could have not verified it like
- * verify(aMock).iHaveSomeDefaultArguments("I'm not gonna pass the second argument", "default value") as the value for the second parameter would have been null...
- */
- override def mock[T <: AnyRef: ClassTag: WeakTypeTag](name: String)(implicit defaultAnswer: DefaultAnswer, $pt: Prettifier): T =
- mock(withSettings.name(name))
-
- def spy[T <: AnyRef: ClassTag: WeakTypeTag](realObj: T, lenient: Boolean = false)(implicit $pt: Prettifier): T = {
- def mockSettings: MockSettings = Mockito.withSettings().defaultAnswer(CALLS_REAL_METHODS).spiedInstance(realObj)
- val settings = if (lenient) mockSettings.strictness(Strictness.LENIENT) else mockSettings
- mock[T](settings)
- }
+/**
+ * Runtime support for MockitoEnhancer with utility methods that don't require WeakTypeTag. Shared across Scala 2 and Scala 3. Version-specific MockitoEnhancer traits extend this.
+ */
+private[mockito] trait MockitoEnhancerRuntime extends MockCreatorRuntime {
/**
* Delegates to Mockito.reset(T... mocks), but restores the default stubs that deal with default argument values
@@ -617,7 +556,7 @@ private[mockito] trait MockitoEnhancer extends MockCreator {
withObject[O](settings.spiedInstance(_), block)
}
- private[mockito] def withObject[O <: AnyRef: ClassTag](settings: O => MockSettings, block: => Any)(implicit $pt: Prettifier) = {
+ private[mockito] def withObject[O <: AnyRef: ClassTag](settings: O => MockSettings, block: => Any)(implicit $pt: Prettifier): Unit = {
val objectClass = clazz[O]
objectClass.synchronized {
val moduleField = objectClass.getDeclaredField("MODULE$")
@@ -625,6 +564,7 @@ private[mockito] trait MockitoEnhancer extends MockCreator {
val threadAwareMock = createMock(
settings(realImpl),
+ List.empty[Class[?]],
(settings: MockCreationSettings[O], pt: Prettifier) => ThreadAwareMockHandler(settings, realImpl)(pt)
)
@@ -633,6 +573,7 @@ private[mockito] trait MockitoEnhancer extends MockCreator {
finally JavaReflectionUtils.setFinalStatic(moduleField, realImpl)
}
}
+
}
trait LeniencySettings {
@@ -702,7 +643,7 @@ private[mockito] trait Verifications {
*
* The idea is based on org.scalatest.mockito.MockitoSugar but it adds 100% of the Mockito API
*
- * It also solve problems like overloaded varargs calls to Java code and pre-stub the mocks so the default arguments in the method parameters work as expected
+ * It also solves problems like overloaded varargs calls to Java code and pre-stub the mocks so the default arguments in the method parameters work as expected
*
* @author
* Bruno Bonanno
diff --git a/scalatest/src/main/scala/org/mockito/scalatest/ResetMocksAfterEachTestBase.scala b/scalatest/src/main/scala-2/org/mockito/scalatest/ResetMocksAfterEachTestCompat.scala
similarity index 56%
rename from scalatest/src/main/scala/org/mockito/scalatest/ResetMocksAfterEachTestBase.scala
rename to scalatest/src/main/scala-2/org/mockito/scalatest/ResetMocksAfterEachTestCompat.scala
index 506e3cec..868e708b 100644
--- a/scalatest/src/main/scala/org/mockito/scalatest/ResetMocksAfterEachTestBase.scala
+++ b/scalatest/src/main/scala-2/org/mockito/scalatest/ResetMocksAfterEachTestCompat.scala
@@ -1,30 +1,17 @@
package org.mockito.scalatest
-import java.util.concurrent.ConcurrentHashMap
-
import org.mockito.stubbing.DefaultAnswer
import org.mockito.{ MockCreator, MockSettings }
import org.scalactic.Prettifier
-import scala.jdk.CollectionConverters.*
import scala.reflect.ClassTag
import scala.reflect.runtime.universe.WeakTypeTag
/**
- * It automatically resets each mock after each test is run, useful when we need to pass the mocks to some framework once at the beginning of the test suite
- *
- * Just mix-in after your favourite suite, i.e. {{{class MyTest extends PlaySpec with MockitoSugar with ResetMocksAfterEachTest}}}
+ * Internal Scala 2 compatibility layer for `ResetMocksAfterEachTest`/`ResetMocksAfterEachAsyncTest`.
+ * Provides WeakTypeTag-based mock override methods that intercept mock creation to track mocks for automatic reset.
*/
-trait ResetMocksAfterEachTestBase extends MockCreator { self: MockCreator =>
-
- private val mocksToReset = ConcurrentHashMap.newKeySet[AnyRef]().asScala
-
- protected def resetAll(): Unit = mocksToReset.foreach(org.mockito.MockitoSugar.reset(_))
-
- private def addMock[T <: AnyRef](mock: T) = {
- mocksToReset.add(mock)
- mock
- }
+private[scalatest] trait ResetMocksAfterEachTestCompat extends MockCreator with ResetMocksAfterEachTestRuntime {
abstract override def mock[T <: AnyRef: ClassTag: WeakTypeTag](implicit defaultAnswer: DefaultAnswer, $pt: Prettifier): T =
addMock(super.mock[T])
diff --git a/scalatest/src/main/scala/org/mockito/scalatest/ResetMocksAfterEachAsyncTest.scala b/scalatest/src/main/scala/org/mockito/scalatest/ResetMocksAfterEachAsyncTest.scala
index d8fbce71..474871d6 100644
--- a/scalatest/src/main/scala/org/mockito/scalatest/ResetMocksAfterEachAsyncTest.scala
+++ b/scalatest/src/main/scala/org/mockito/scalatest/ResetMocksAfterEachAsyncTest.scala
@@ -3,11 +3,11 @@ package org.mockito.scalatest
import org.scalatest.{ AsyncTestSuite, FutureOutcome }
/**
- * It automatically resets each mock after a each test is run, useful when we need to pass the mocks to some framework once at the beginning of the test suite
+ * It automatically resets each mock after each test is run, useful when we need to pass the mocks to some framework once at the beginning of the test suite
*
* Just mix-in after your favourite suite, i.e. {{{class MyTest extends PlaySpec with MockitoSugar with ResetMocksAfterEachAsyncTest}}}
*/
-trait ResetMocksAfterEachAsyncTest extends AsyncTestSuite with ResetMocksAfterEachTestBase {
+trait ResetMocksAfterEachAsyncTest extends AsyncTestSuite with ResetMocksAfterEachTestCompat {
override def withFixture(test: NoArgAsyncTest): FutureOutcome =
super.withFixture(test).onCompletedThen(_ => resetAll())
diff --git a/scalatest/src/main/scala/org/mockito/scalatest/ResetMocksAfterEachTest.scala b/scalatest/src/main/scala/org/mockito/scalatest/ResetMocksAfterEachTest.scala
index aea899a5..ec0ce159 100644
--- a/scalatest/src/main/scala/org/mockito/scalatest/ResetMocksAfterEachTest.scala
+++ b/scalatest/src/main/scala/org/mockito/scalatest/ResetMocksAfterEachTest.scala
@@ -3,11 +3,11 @@ package org.mockito.scalatest
import org.scalatest.{ Outcome, TestSuite }
/**
- * It automatically resets each mock after a each test is run, useful when we need to pass the mocks to some framework once at the beginning of the test suite
+ * It automatically resets each mock after each test is run, useful when we need to pass the mocks to some framework once at the beginning of the test suite
*
* Just mix-in after your favourite suite, i.e. {{{class MyTest extends PlaySpec with MockitoSugar with ResetMocksAfterEachTest}}}
*/
-trait ResetMocksAfterEachTest extends TestSuite with ResetMocksAfterEachTestBase {
+trait ResetMocksAfterEachTest extends TestSuite with ResetMocksAfterEachTestCompat {
override protected def withFixture(test: NoArgTest): Outcome = {
val outcome = super.withFixture(test)
diff --git a/scalatest/src/main/scala/org/mockito/scalatest/ResetMocksAfterEachTestRuntime.scala b/scalatest/src/main/scala/org/mockito/scalatest/ResetMocksAfterEachTestRuntime.scala
new file mode 100644
index 00000000..6aaf5b4a
--- /dev/null
+++ b/scalatest/src/main/scala/org/mockito/scalatest/ResetMocksAfterEachTestRuntime.scala
@@ -0,0 +1,20 @@
+package org.mockito.scalatest
+
+import java.util.concurrent.ConcurrentHashMap
+import scala.jdk.CollectionConverters.*
+
+/**
+ * Runtime support for ResetMocksAfterEachTestBase. Shared across Scala 2 and Scala 3.
+ */
+trait ResetMocksAfterEachTestRuntime {
+
+ private val mocksToReset = ConcurrentHashMap.newKeySet[AnyRef]().asScala
+
+ protected def resetAll(): Unit = mocksToReset.foreach(org.mockito.MockitoSugar.reset(_))
+
+ private[scalatest] def addMock[T <: AnyRef](mock: T): T = {
+ mocksToReset.add(mock)
+ mock
+ }
+
+}
diff --git a/scalatest/src/test/scala/user/org/mockito/IdiomaticStubbingTest.scala b/scalatest/src/test/scala/user/org/mockito/IdiomaticStubbingTest.scala
index b07bd866..1d1f1e60 100644
--- a/scalatest/src/test/scala/user/org/mockito/IdiomaticStubbingTest.scala
+++ b/scalatest/src/test/scala/user/org/mockito/IdiomaticStubbingTest.scala
@@ -373,5 +373,27 @@ class IdiomaticStubbingTest extends AnyWordSpec with Matchers with ArgumentMatch
else FooObject.stateDependantMethod shouldBe now
}
}
+
+ "stub methods from traits in object" in {
+ ObjectWithTraits.methodFromTraitA shouldBe "TraitA implementation"
+ ObjectWithTraits.methodFromTraitB shouldBe 42
+
+ withObjectMocked[ObjectWithTraits.type] {
+ // Verify the mock implements the trait interfaces
+ ObjectWithTraits shouldBe a[TraitA]
+ ObjectWithTraits shouldBe a[TraitB]
+
+ ObjectWithTraits.methodFromTraitA returns "mocked A"
+ ObjectWithTraits.methodFromTraitB returns 99
+ ObjectWithTraits.ownMethod returns "mocked own"
+
+ ObjectWithTraits.methodFromTraitA shouldBe "mocked A"
+ ObjectWithTraits.methodFromTraitB shouldBe 99
+ ObjectWithTraits.ownMethod shouldBe "mocked own"
+ }
+
+ ObjectWithTraits.methodFromTraitA shouldBe "TraitA implementation"
+ ObjectWithTraits.methodFromTraitB shouldBe 42
+ }
}
}
diff --git a/scalatest/src/test/scala/user/org/mockito/TestModel.scala b/scalatest/src/test/scala/user/org/mockito/TestModel.scala
index b054ca5b..9e8819f1 100644
--- a/scalatest/src/test/scala/user/org/mockito/TestModel.scala
+++ b/scalatest/src/test/scala/user/org/mockito/TestModel.scala
@@ -135,3 +135,15 @@ object FooObject {
def stateDependantMethod: Long = now
}
+
+trait TraitA {
+ def methodFromTraitA: String = "TraitA implementation"
+}
+
+trait TraitB {
+ def methodFromTraitB: Int = 42
+}
+
+object ObjectWithTraits extends TraitA with TraitB {
+ def ownMethod: String = "own method"
+}