I'm trying to mock cats.effect.IO
by
val ioSql: IO[Sql[IO, SqlConnection[IO]]] = mock[IO[Sql[IO, SqlConnection[IO]]]]
Sql
and SqlConnection
are my company libraries.
I've got this error
Underlying exception : java.lang.reflect.MalformedParameterizedTypeException
------------------------------------------------------------
org.mockito.exceptions.base.MockitoException:
Mockito cannot mock this class: class cats.effect.IO.
Mockito can only mock non-private & non-final classes.
If you're not sure why you're getting this error, please report to the mailing list.
Java : 1.8
JVM vendor name : Azul Systems, Inc.
JVM vendor version : 25.192-b01
JVM name : OpenJDK 64-Bit Server VM
JVM version : 1.8.0_192-b01
JVM info : mixed mode
OS name : Windows 10
OS version : 10.0
Underlying exception : java.lang.reflect.MalformedParameterizedTypeException
at org.specs2.mock.MockitoMocker.mock(MockitoMocker.scala:21)
at org.specs2.mock.MockitoMocker.mock$(MockitoMocker.scala:21)
at org.specs2.mock.mockito.TheMockitoMocker$$anon$1.mock(TheMockitoMocker.scala:8)
at org.specs2.mock.mockito.MocksCreation.mock(MocksCreation.scala:18)
at org.specs2.mock.mockito.MocksCreation.mock$(MocksCreation.scala:18)
at com.foo.BarSpec.mock(BarSpec.scala:15)
at com.goo.BarSpec.$anonfun$new$1(BarSpec.scala:21)
at org.specs2.specification.dsl.mutable.EffectBlocks.tryBlock(EffectBlocks.scala:131)
at org.specs2.specification.dsl.mutable.EffectBlocks.$anonfun$nestBlock$2(EffectBlocks.scala:110)
at org.specs2.specification.dsl.mutable.EffectBlocks.record(EffectBlocks.scala:61)
at org.specs2.specification.dsl.mutable.MutableFragmentBuilder.$anonfun$replayFragments$2(MutableFragmentBuilder.scala:47)
at scala.Option.getOrElse(Option.scala:189)
at org.specs2.specification.dsl.mutable.MutableFragmentBuilder.replayFragments(MutableFragmentBuilder.scala:47)
at org.specs2.specification.dsl.mutable.MutableFragmentBuilder.specificationFragments(MutableFragmentBuilder.scala:37)
at org.specs2.specification.dsl.mutable.MutableFragmentBuilder.specificationFragments$(MutableFragmentBuilder.scala:36)
at org.specs2.mutable.Specification.specificationFragments(Specification.scala:15)
at org.specs2.specification.dsl.mutable.MutableFragmentBuilder.$anonfun$is$1(MutableFragmentBuilder.scala:44)
at org.specs2.specification.core.SpecStructure.fragments$lzycompute(SpecStructure.scala:26)
at org.specs2.specification.core.SpecStructure.fragments(SpecStructure.scala:26)
at org.specs2.specification.core.SpecStructure.$anonfun$map$1(SpecStructure.scala:29)
at org.specs2.specification.core.SpecStructure.fragments$lzycompute(SpecStructure.scala:26)
at org.specs2.specification.core.SpecStructure.fragments(SpecStructure.scala:26)
at org.specs2.specification.core.SpecStructure.$anonfun$$bar$greater$1(SpecStructure.scala:30)
at org.specs2.specification.core.SpecStructure.fragments$lzycompute(SpecStructure.scala:26)
at org.specs2.specification.core.SpecStructure.fragments(SpecStructure.scala:26)
at org.specs2.specification.core.SpecStructure.$anonfun$$bar$greater$1(SpecStructure.scala:30)
at org.specs2.specification.core.SpecStructure.fragments$lzycompute(SpecStructure.scala:26)
at org.specs2.specification.core.SpecStructure.fragments(SpecStructure.scala:26)
at org.specs2.specification.core.SpecStructure.contents(SpecStructure.scala:28)
at org.specs2.reporter.Reporter.$anonfun$report$1(Reporter.scala:43)
at org.specs2.runner.Runner$.runSpecStructure(Runner.scala:109)
at org.specs2.runner.ClassRunner.$anonfun$report$2(ClassRunner.scala:59)
at org.specs2.control.eff.Arrs.go$1(Eff.scala:386)
at org.specs2.control.eff.Arrs.apply(Eff.scala:399)
at org.specs2.control.eff.Arrs.apply(Eff.scala:348)
at org.specs2.control.eff.CollectedUnions.$anonfun$continuation$1(Unions.scala:84)
at org.specs2.control.eff.Arrs.go$1(Eff.scala:383)
at org.specs2.control.eff.Arrs.apply(Eff.scala:399)
at org.specs2.control.eff.Interpret$$anon$1.$anonfun$onEffect$1(Interpret.scala:53)
at org.specs2.fp.EitherOps$.bimap$extension(EitherSyntax.scala:82)
at org.specs2.control.eff.Interpret$$anon$1.onEffect(Interpret.scala:53)
at org.specs2.control.eff.Interpret$$anon$1.onApplicativeEffect(Interpret.scala:61)
at org.specs2.control.eff.Interpret$$anon$1.onApplicativeEffect(Interpret.scala:45)
at org.specs2.control.eff.Interpret.go$1(Interpret.scala:200)
at org.specs2.control.eff.Interpret.interpretLoop(Interpret.scala:207)
at org.specs2.control.eff.Interpret.interpretLoop$(Interpret.scala:142)
at org.specs2.control.eff.Interpret$.interpretLoop(Interpret.scala:635)
at org.specs2.control.eff.Interpret.interpret(Interpret.scala:71)
at org.specs2.control.eff.Interpret.interpret$(Interpret.scala:44)
at org.specs2.control.eff.Interpret$.interpret(Interpret.scala:635)
at org.specs2.control.eff.Interpret.interpret1(Interpret.scala:78)
at org.specs2.control.eff.Interpret.interpret1$(Interpret.scala:77)
at org.specs2.control.eff.Interpret$.interpret1(Interpret.scala:635)
at org.specs2.control.eff.ErrorInterpretation.runError(ErrorEffect.scala:87)
at org.specs2.control.eff.ErrorInterpretation.runError$(ErrorEffect.scala:68)
at org.specs2.control.eff.ErrorEffect$.runError(ErrorEffect.scala:187)
at org.specs2.control.eff.syntax.error$ErrorEffectOps.runError(error.scala:14)
at org.specs2.control.ExecuteActions.attemptExecuteAction(ExecuteActions.scala:59)
at org.specs2.control.ExecuteActions.attemptExecuteAction$(ExecuteActions.scala:56)
at org.specs2.control.ExecuteActions$.attemptExecuteAction(ExecuteActions.scala:93)
at org.specs2.runner.Runner$.execute(Runner.scala:28)
at org.specs2.runner.ClassRunner.run(ClassRunner.scala:46)
at org.specs2.runner.ClassRunner.run$(ClassRunner.scala:31)
at org.specs2.runner.ClassRunner$.run(ClassRunner.scala:79)
at org.specs2.runner.ClassRunner.run(ClassRunner.scala:25)
at org.specs2.runner.ClassRunner.run$(ClassRunner.scala:24)
at org.specs2.runner.ClassRunner$.run(ClassRunner.scala:79)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.jetbrains.plugins.scala.testingSupport.specs2.Specs2Runner.runWithNotifierRunner(Specs2Runner.java:154)
at org.jetbrains.plugins.scala.testingSupport.specs2.Specs2Runner.runSpecs2_new(Specs2Runner.java:144)
at org.jetbrains.plugins.scala.testingSupport.specs2.Specs2Runner.main(Specs2Runner.java:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.CommandLineWrapper.main(CommandLineWrapper.java:63)
Caused by: java.lang.reflect.MalformedParameterizedTypeException
at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.validateConstructorArguments(ParameterizedTypeImpl.java:58)
at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.<init>(ParameterizedTypeImpl.java:51)
at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.make(ParameterizedTypeImpl.java:92)
at sun.reflect.generics.factory.CoreReflectionFactory.makeParameterizedType(CoreReflectionFactory.java:105)
at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:140)
at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:49)
at sun.reflect.generics.repository.MethodRepository.getReturnType(MethodRepository.java:68)
at java.lang.reflect.Method.getGenericReturnType(Method.java:255)
at net.bytebuddy.description.type.TypeDescription$Generic$LazyProjection$ForLoadedReturnType.resolve(TypeDescription.java:6512)
at net.bytebuddy.description.type.TypeDescription$Generic$LazyProjection.accept(TypeDescription.java:6106)
at net.bytebuddy.description.method.MethodDescription$TypeSubstituting.getReturnType(MethodDescription.java:1607)
at net.bytebuddy.description.method.MethodDescription$AbstractBase.asSignatureToken(MethodDescription.java:838)
at net.bytebuddy.matcher.SignatureTokenMatcher.matches(SignatureTokenMatcher.java:47)
at net.bytebuddy.matcher.SignatureTokenMatcher.matches(SignatureTokenMatcher.java:26)
at net.bytebuddy.matcher.ElementMatcher$Junction$Conjunction.matches(ElementMatcher.java:122)
at net.bytebuddy.matcher.FilterableList$AbstractBase.filter(FilterableList.java:125)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassImplementationTarget.invokeConstructor(SubclassImplementationTarget.java:76)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassImplementationTarget.invokeSuper(SubclassImplementationTarget.java:62)
at net.bytebuddy.implementation.Implementation$Target$AbstractBase.invokeDominant(Implementation.java:442)
at net.bytebuddy.implementation.SuperMethodCall$Appender.apply(SuperMethodCall.java:130)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyCode(TypeWriter.java:713)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyBody(TypeWriter.java:698)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod.apply(TypeWriter.java:605)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForCreation.create(TypeWriter.java:5133)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1933)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:225)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:198)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3404)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:3600)
at org.mockito.internal.creation.bytebuddy.SubclassBytecodeGenerator.mockClass(SubclassBytecodeGenerator.java:173)
at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator$1.call(TypeCachingBytecodeGenerator.java:37)
at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator$1.call(TypeCachingBytecodeGenerator.java:34)
at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:152)
at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:365)
at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:174)
at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:376)
at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator.mockClass(TypeCachingBytecodeGenerator.java:32)
at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMockType(SubclassByteBuddyMockMaker.java:71)
at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMock(SubclassByteBuddyMockMaker.java:42)
at org.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker.createMock(ByteBuddyMockMaker.java:25)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:35)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:63)
at org.mockito.Mockito.mock(Mockito.java:1908)
at org.mockito.Mockito.mock(Mockito.java:1817)
... 79 more
The question is when I used the older version of my company libraries, the tests pass with no error.
Both of org.typelevel.cats-effect
and org.mockito.mockito-core
are the same version on both older and newer version of my company libraries.
Do. Not. Mock. Values.
You don't mock Strings, Booleans or Ints (I hope). ADTs are in the same category:
case class
esobject
sEither
sOption
ssealed trait
sThey are data. You don't mock data. You pass data.
You mock behavior (if you cannot really avoid it). Except it the behavior is a function. You do not mock function, because it makes 0 sense. You can create it ad hoc and pass just like that.
Instead of:
val ioSql: IO[Sql[IO, SqlConnection[IO]]] = mock[IO[Sql[IO, SqlConnection[IO]]]]
you could simply:
val ioSql: IO[Sql[IO, SqlConnection[IO]]] = IO {
// here create Sql[IO, SqlConnection[IO]]] value
// I mean if you want to mock it you virtually have to create it anyway
// you can even put side effects here if you want to check that
// IO was evaluated or sth
}
or maybe
val ioSql: IO[Sql[IO, SqlConnection[IO]]] = IO.raiseError(
new Exception("No SQL for you")
)
Mocking everything is a foolish habit. Mocking is a way of lessen the burden of creating a value to return during tests in where the alternative would be to create a whole fake class implementation where there is 50 methods and only 2 of them are needed. It's not the case when you are using things that should be treated as values. You wouldn't use powermock to check if you class handles properly the case where String.size
throws, because it doesn't by design. Same for ADTs. They can be create in one liner, their hebavior depends only of what data you put it. There is no reasonable use case for mocking, stubbing or faking them if. It true ether we are talking about Either, Option, Tuple, case class, enum or IO monad.