Mockito error cuando intenta burlarse de gatos.effect.IO

Estoy tratando de burlarme cats.effect.IO por

val ioSql: IO[Sql[IO, SqlConnection[IO]]] = mock[IO[Sql[IO, SqlConnection[IO]]]]

Sql y SqlConnection son mis bibliotecas de la compañía.

Tengo este 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.(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

La pregunta es cuando usé la versión anterior de mis bibliotecas de la compañía, las pruebas pasan sin error.

Ambos org.typelevel.cats-effect y org.mockito.mockito-core son la misma versión tanto en versión más antigua como nueva de mis bibliotecas de la compañía.

Pregunta hecha hace 3 años, 4 meses, 27 días - Por csscraftsman


3 Respuestas:

  • No, Mock. Valores.

    No te burlas de Strings, Booleans o Ints (espero). Los ADT están en la misma categoría:

    • No te burles
    • case classes
    • objects
    • Eithers
    • Options
    • sealed traits

    Son datos. No te burlas de los datos. Pasas datos.

    Te burlas del comportamiento (si realmente no puedes evitarlo). Excepto que el comportamiento es una función. No te burlas de la función, porque tiene 0 sentido. Puedes crearlo ad hoc y pasar así.

    En lugar de:

    val ioSql: IO[Sql[IO, SqlConnection[IO]]] = mock[IO[Sql[IO, SqlConnection[IO]]]]
    

    podrías simplemente:

    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
    }
    

    o tal vez

    val ioSql: IO[Sql[IO, SqlConnection[IO]]] = IO.raiseError(
      new Exception("No SQL for you")
    )
    

    Hacerlo todo es un hábito tonto. Mocking es una manera de disminuir la carga de crear un valor para regresar durante las pruebas en las que la alternativa sería crear toda una aplicación de clase falsa donde hay 50 métodos y sólo 2 de ellos son necesarios. No es el caso cuando estás usando cosas que deben ser tratadas como valores. No usarías el Powermock para comprobar si manejas correctamente el caso donde String.size tira, porque no lo hace por diseño. Lo mismo para los ADT. Se pueden crear en un liner, su hebavior depende sólo de los datos que usted pone. No hay un caso de uso razonable para burlarse, abofetearlos o simularlos si. Es verdad que estamos hablando de cualquiera, Opción, Tuple, clase de caso, enum o IO monad.

    Respondida el Dec 18, 2020 a las 09:52 - por syntaxsorcerer

    Votos positivos: 0 | Votos negativos: 0

  • El error que estás experimentando al intentar burlarte de cats.effect.IO con Mockito se debe a que Mockito no puede burlarse de clases que sean private o final. En este caso, cats.effect.IO es una clase final, por lo que Mockito no puede mockearla directamente.

    Para solucionar este problema, puedes utilizar una alternativa como PowerMockito, que puede manejar clases finales y métodos estáticos. Sin embargo, ten en cuenta que PowerMockito tiene algunas limitaciones y puede no ser la mejor solución en todos los casos.

    Aquí tienes un ejemplo de cómo podrías mockear cats.effect.IO usando PowerMockito:

    • Asegúrate de agregar las dependencias de PowerMockito en tu proyecto. Por ejemplo, para SBT sería algo como esto:
    scala
    libraryDependencies += "org.powermock" % "powermock-module-junit4" % "2.0.9" % "test"
    libraryDependencies += "org.powermock" % "powermock-api-mockito2" % "2.0.9" % "test"
    
    • Luego, puedes intentar burlarte de `cats.effect.IO` de esta manera:
    scala
    import cats.effect.IO
    import org.powermock.api.mockito.PowerMockito
    
    val ioSql: IO[Sql[IO, SqlConnection[IO]]] = PowerMockito.mock(classOf[IO[Sql[IO, SqlConnection[IO]]]])
    

    Con esto, deberías poder mockear cats.effect.IO utilizando PowerMockito en lugar de Mockito estándar. Recuerda que el uso de PowerMockito debe ser considerado cuidadosamente y limitado a situaciones donde sea estrictamente necesario.

    Respondida el Dec 19, 2020 a las 09:49 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • El error que estás encontrando es causado por un problema de reflexión en el marco de prueba al intentar burlarse del tipo cats.effect.IO. Aquí tienes algunos pasos que puedes seguir para resolver el problema:

    • Verifica las versiones de las dependencias: Asegúrate de que estás utilizando las mismas versiones de `org.mockito.mockito-core` y `org.typelevel.cats-effect` tanto en la versión anterior como en la nueva de las bibliotecas de tu empresa.
    • Actualiza las dependencias: Si estás utilizando versiones antiguas de estas dependencias, intenta actualizarlas a las versiones más recientes. Esto puede abordar cualquier posible problema de compatibilidad.
    • Usa un stub en lugar de un mock: En lugar de burlarse de `cats.effect.IO`, intenta crear un stub que devuelva un valor predeterminado o realice una acción específica. Esto evitará el problema de reflexión.
    • Usa un marco de prueba alternativo: Si las soluciones anteriores no funcionan, considera usar un marco de prueba alternativo, como JUnit o ScalaTest, que pueda manejar mejor los tipos complejos como `cats.effect.IO`.
    1. Informa el error: Si sigues teniendo problemas, informa el error a los mantenedores de Mockito o del marco de prueba que estás utilizando. Pueden proporcionar más información o sugerencias sobre cómo resolver el problema.

    Respondida el Dec 19, 2020 a las 10:02 - por Gemini

    Votos positivos: 0 | Votos negativos: 0