You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I recently ran into a situation where PrivateMethod/PrivateMethodTester does not seem to correctly honor the type bounds defined for arguments to the method being tested. I put together the code below to illustrate a simplified example of what I'm seeing.
Here are some definitions that mimic the structure of the code used in my application:
// Abstract class and marker traits to set up test conditionsabstractclassThingtraitHasPropertyAtraitHasPropertyB// Concrete implementations for testsclassThingWithPropertyAextendsThingwithHasPropertyAclassThingWithPropertiesAAndBextendsThingwithHasPropertyAwithHasPropertyB// Object containing methods to testobjectTestClass {
defdoSomething[T<:ThingwithHasPropertyAwithHasPropertyB](
thing: T
):String= {
s"thing: $thing"
}
privatedefdoSomethingPrivately[T<:ThingwithHasPropertyAwithHasPropertyB](
thing: T
):String= doSomething(thing)
}
This test code (with comments showing the results when run) demonstrates the problem:
importorg.scalatest.PrivateMethodTesterimportorg.scalatest.freespec.AnyFreeSpecimportorg.scalatest.matchers.should.MatchersclassPrivateMethodTesterSpecextendsAnyFreeSpecwithMatcherswithPrivateMethodTester {
valthingA=newThingWithPropertyAvalthingAB=newThingWithPropertiesAAndB// PASS"doSomething() should work for correctly typed Things" in {
TestClass.doSomething(thingAB) shouldEqual s"thing: $thingAB"
}
// PASS"calling doSomething() with incorrectly typed Things should not type check" in {
"TestClass.doSomething(thingA)" shouldNot typeCheck
}
valdoSomethingPrivately=PrivateMethod[String](Symbol("doSomethingPrivately"))
// PASS"doSomethingPrivately() should work for correctly typed Things" in {
TestClass.invokePrivate(doSomethingPrivately(thingAB)) shouldEqual s"thing: $thingAB"
}
// FAIL"calling doSomethingPrivately() with incorrectly typed Things should not type check" in {
"TestClass.invokePrivate(doSomethingPrivately(thingA))" shouldNot typeCheck
}
// PASS"calling doSomethingPrivately() with incorrectly typed Things should not type check but works anyway" in {
TestClass.invokePrivate(doSomethingPrivately(thingA)) shouldEqual s"thing: $thingA"
}
}
And here's the raw test output:
[info] PrivateMethodTesterSpec:
[info] - doSomething() should work for correctly typed Things
[info] - calling doSomething() with incorrectly typed Things should not type check
[info] - doSomethingPrivately() should work for correctly typed Things
[info] - calling doSomethingPrivately() with incorrectly typed Things should not type check *** FAILED ***
[info] Expected a type error, but got none for code: TestClass.invokePrivate(doSomethingPrivately(thingA)) (PrivateMethodTesterSpec.scala:54)
[info] - calling doSomethingPrivately() with incorrectly typed Things should not type check but works anyway
[info] Run completed in 1 second, 214 milliseconds.
[info] Total number of tests run: 5
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 4, failed 1, canceled 0, ignored 0, pending 0
[info] *** 1 TEST FAILED ***
In addition to the type checking not working for the private method, I was very surprised to see that doSomethingPrivately() successfully passes the ThingWithPropertyA to doSomething() and receives a result, despite doSomething()also requiring that the Thing extends both HasPropertyA and HasPropertyB. I made some adjustments to see what happened if doSomething() tried to access a property that only existed in HasPropertyB, and it looks like invokePrivate might be just trying to cast the input arguments as the expected types? This would explain why it works in some cases but not all.
...
traitHasPropertyB {
valpropB:String="b"
}
...
defdoSomething[T<:ThingwithHasPropertyAwithHasPropertyB](
thing: T
):String= {
s"thing: $thing (${thing.propB})"
}
...
// NOTE: NO LONGER PASSES! SEE OUTPUT BELOW"calling doSomethingPrivately() with incorrectly typed Things should not type check but works anyway" in {
TestClass.invokePrivate(doSomethingPrivately(thingA)) shouldEqual s"thing: $thingA (b)"
}
...
[info] - calling doSomethingPrivately() with incorrectly typed Things should not type check but works anyway *** FAILED ***
[info] java.lang.ClassCastException: class <mypackage>.ThingWithPropertyA cannot be cast to class <mypackage>.HasPropertyB (<mypackage>.ThingWithPropertyA and <mypackage>.HasPropertyB are in unnamed module of loader 'app')
[info] at <mypackage>.TestClass$.doSomething(PrivateMethodTesterSpec.scala:24)
[info] at <mypackage>.TestClass$.doSomethingPrivately(PrivateMethodTesterSpec.scala:29)
[info] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[info] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
[info] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[info] at java.base/java.lang.reflect.Method.invoke(Method.java:568)
[info] at org.scalatest.PrivateMethodTester$Invoker.invokePrivate(PrivateMethodTester.scala:260)
[info] at <mypackage>.PrivateMethodTesterSpec.$anonfun$new$6(PrivateMethodTesterSpec.scala:71)
[info] at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
[info] at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
[info] ...
I'm using ScalaTest 3.2.16, Scala 2.13.10, Java 17.
The text was updated successfully, but these errors were encountered:
I recently ran into a situation where
PrivateMethod
/PrivateMethodTester
does not seem to correctly honor the type bounds defined for arguments to the method being tested. I put together the code below to illustrate a simplified example of what I'm seeing.Here are some definitions that mimic the structure of the code used in my application:
This test code (with comments showing the results when run) demonstrates the problem:
And here's the raw test output:
In addition to the type checking not working for the private method, I was very surprised to see that
doSomethingPrivately()
successfully passes theThingWithPropertyA
todoSomething()
and receives a result, despitedoSomething()
also requiring that theThing
extends bothHasPropertyA
andHasPropertyB
. I made some adjustments to see what happened ifdoSomething()
tried to access a property that only existed inHasPropertyB
, and it looks likeinvokePrivate
might be just trying to cast the input arguments as the expected types? This would explain why it works in some cases but not all.I'm using ScalaTest 3.2.16, Scala 2.13.10, Java 17.
The text was updated successfully, but these errors were encountered: