看起来像是sbt classload和mockito。
project/build.scala
import sbt._
import Keys._
import sbtassembly.Plugin._
import AssemblyKeys._
object Build extends Build {
lazy val root = project.in(file("."))
.settings(
name := "so-mockito",
compileOrder := CompileOrder.JavaThenScala,
libraryDependencies += "org.mockito" % "mockito-core" % "1.9.5"
)
.settings(buildSettings: _*)
.settings(assemblySettings: _*)
.settings(mainClass in assembly := Some("com.example.JavaMain"))
}
project/plugins.sbt
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.10.2")
src/main/java/com/example/consumer.java
package com.example;
class Consumer {
interface Input {
String get();
}
private final Input input;
static Consumer create(Input input) {
return new Consumer(input);
}
private Consumer(Input input) {
this.input = input;
}
}
src/main/java/com/example/javamain.java
package com.example;
import static org.mockito.Mockito.*;
import static com.example.Consumer.*;
public class JavaMain {
public static void main(String[] args) {
final Input input = mock(Input.class);
System.out.println(String.format("[JavaMain] Created mock: '%s'", input));
}
}
sbt run
产生以下例外:
[info] Running com.example.JavaMain
[error] (run-main-0) org.mockito.exceptions.base.MockitoException:
[error] Mockito cannot mock this class: interface com.example.Consumer$Input
[error] Mockito can only mock visible & non-final classes.
[error] If you're not sure why you're getting this error, please report to the mailing list.
org.mockito.exceptions.base.MockitoException:
Mockito cannot mock this class: interface com.example.Consumer$Input
Mockito can only mock visible & non-final classes.
If you're not sure why you're getting this error, please report to the mailing list.
at com.example.JavaMain.main(JavaMain.java:8)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
Caused by: org.mockito.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:238)
at org.mockito.cglib.proxy.Enhancer.createHelper(Enhancer.java:378)
at org.mockito.cglib.proxy.Enhancer.createClass(Enhancer.java:318)
at org.mockito.internal.creation.jmock.ClassImposterizer.createProxyClass(ClassImposterizer.java:110)
at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:62)
at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:56)
at org.mockito.internal.creation.CglibMockMaker.createMock(CglibMockMaker.java:23)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:26)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:51)
at org.mockito.Mockito.mock(Mockito.java:1243)
at org.mockito.Mockito.mock(Mockito.java:1120)
at com.example.JavaMain.main(JavaMain.java:8)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.mockito.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:385)
at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:220)
at org.mockito.cglib.proxy.Enhancer.createHelper(Enhancer.java:378)
at org.mockito.cglib.proxy.Enhancer.createClass(Enhancer.java:318)
at org.mockito.internal.creation.jmock.ClassImposterizer.createProxyClass(ClassImposterizer.java:110)
at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:62)
at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:56)
at org.mockito.internal.creation.CglibMockMaker.createMock(CglibMockMaker.java:23)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:26)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:51)
at org.mockito.Mockito.mock(Mockito.java:1243)
at org.mockito.Mockito.mock(Mockito.java:1120)
at com.example.JavaMain.main(JavaMain.java:8)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
Caused by: java.lang.IllegalAccessError: class com.example.Consumer$Input$$EnhancerByMockitoWithCGLIB$$5997e3ec cannot access its superinterface com.example.Consumer$Input
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.mockito.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:385)
at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:220)
at org.mockito.cglib.proxy.Enhancer.createHelper(Enhancer.java:378)
at org.mockito.cglib.proxy.Enhancer.createClass(Enhancer.java:318)
at org.mockito.internal.creation.jmock.ClassImposterizer.createProxyClass(ClassImposterizer.java:110)
at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:62)
at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:56)
at org.mockito.internal.creation.CglibMockMaker.createMock(CglibMockMaker.java:23)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:26)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:51)
at org.mockito.Mockito.mock(Mockito.java:1243)
at org.mockito.Mockito.mock(Mockito.java:1120)
at com.example.JavaMain.main(JavaMain.java:8)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
但是,使用java
或scala
运行,按预期运行:
> sbt assembly && java -jar target/scala-2.10/so-mockito-assembly-0.1-SNAPSHOT.jar
[JavaMain] Created mock: 'Mock for Input, hashCode: 1317029026'
> sbt assembly && scala -cp target/scala-2.10/so-mockito-assembly-0.1-SNAPSHOT.jar 'com.example.JavaMain'
[JavaMain] Created mock: 'Mock for Input, hashCode: 1035091326'
任何人都可以确认(SBT 0.13.1)?
当内部com.example.Consumer.Input
接口的访问修改器变为 public
时,它可以正常工作(注意接口的public
关键字):
package com.example;
class Consumer {
public interface Input {
String get();
}
private final Input input;
static Consumer create(Input input) {
return new Consumer(input);
}
private Consumer(Input input) {
this.input = input;
}
}
以前使用about
的示例sbt run
,以了解版本,插件等。
$ sbt about run
[info] Loading global plugins from /Users/jacek/.sbt/0.13/plugins
[info] Loading project definition from /Users/jacek/sandbox/so/mockito/project
[info] Set current project to so-mockito (in build file:/Users/jacek/sandbox/so/mockito/)
[info] This is sbt 0.13.1
[info] The current project is {file:/Users/jacek/sandbox/so/mockito/}root 0.1-SNAPSHOT
[info] The current project is built against Scala 2.10.3
[info] Available Plugins: com.typesafe.sbt.SbtGit, com.typesafe.sbt.SbtProguard, growl.GrowlingTests, np.Plugin, com.timushev.sbt.updates.UpdatesPlugin, sbtassembly.Plugin
[info] sbt, sbt plugins, and build definitions are using Scala 2.10.3
[info] Running com.example.JavaMain
[JavaMain] Created mock: 'Mock for Input, hashCode: 256995217'
[success] Total time: 0 s, completed Jan 29, 2014 10:00:13 PM
btw,在这种特定的构建配置中,使用build.sbt
可能是一个更好的选择,因为它会变得更加清晰。
build.sbt
import AssemblyKeys._
name := "so-mockito"
compileOrder := CompileOrder.JavaThenScala
libraryDependencies += "org.mockito" % "mockito-core" % "1.9.5"
sbtassembly.Plugin.buildSettings
sbtassembly.Plugin.assemblySettings
mainClass in assembly := Some("com.example.JavaMain")
我在嘲笑Scala代码mock[org.flywaydb.core.Flyway]
的飞行时被类似错误击败,测试通过Intellij很好地进行,但是通过它提出的SBT测试:
java.lang.IllegalAccessError: tried to access class org.flywaydb.core.Flyway
对于其他Googles,我的解决方案只是升级Mockito Core:
```````` - " org.mockito"%" Mockito-Core"%" 2.7.22", " org.mockito"%" Mockito-Core"%" 2.15.0",
````