Robolectric + Mockito - "Wanted but not invoked"
Robolectric + Mockito - "Wanted but not invoked"
我正在尝试学习 Robolectric
和 Mockito
,以实现我正在为已经运行的 Android 项目创建测试。但我遇到了一些麻烦。这将使您了解我正在尝试测试的 Activity:
public class MainActivity extends FragmentActivity {
public Session session;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
session = getActiveSession();
if (session == null ) {
// ...
} else {
if (sessionClosed()) {
LoginFragment fragment = new LoginFragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.container, fragment);
ft.commit();
}
}
}
...
public Session getActiveSession() {
return Session.getActiveSession();
}
public boolean sessionClosed() {
return session.isClosed();
}
}
这段代码的作用是获取活动 Facebook
会话,并根据其状态显示不同的 Fragment
。现在我将向您展示测试 class:
@RunWith(RobolectricTestRunner.class)
public class MainActivityTest {
private ActivityController<?> controller;
private MainActivity activity;
private MainActivity spy;
@Before
public void setup() throws Exception {
controller = Robolectric.buildActivity(MainActivity.class);
activity = (MainActivity) controller.create().get();
spy = Mockito.spy(activity);
}
@Test
public void testShowLoginWhenSessionClosed() {
Session session = new Session(Robolectric.application);
Mockito.doReturn(session).when(spy).getActiveSession();
Mockito.doReturn(true).when(spy).sessionClosed();
Mockito.verify(spy).getActiveSession();
Fragment fragment = activity.getSupportFragmentManager()
.findFragmentById(R.id.container);
Assert.assertTrue(fragment instanceof LoginFragment);
}
}
如您所见,我在单独的 java 项目中使用 Robolectric 和 Mockito。当我运行测试时 class 我得到以下信息:
Wanted but not invoked:
mainActivity.getActiveSession();
-> at org.example.MainActivityTest.testShowLoginWhenSessionClosed(MainActivityTest.java:101)
Actually, there were zero interactions with this mock.
at org.example.MainActivityTest.testShowLoginWhenSessionClosed(MainActivityTest.java:101)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:236)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access[=14=]0(ParentRunner.java:50)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:222)
at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:158)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
你能帮我处理一下吗?
编辑
我摆脱了 Activity 控制器,看看手动处理生命周期是否有效,但我收到相同的 "Wanted but not invoked" 消息:
@Test
public void testShowLoginWhenSessionClosed() throws Exception {
Session session = new Session(Robolectric.application);
MainActivity myActivity = Mockito.mock(MainActivity.class);
Mockito.when(myActivity.getActiveSession()).thenReturn(session);
Mockito.when(myActivity.sessionClosed()).thenReturn(true);
myActivity.onCreate(null);
myActivity.getActiveSession(); // works only if i call it manually
Mockito.verify(myActivity).getActiveSession();
Fragment fragment = myActivity.getSupportFragmentManager()
.findFragmentById(R.id.container);
Assert.assertTrue(fragment instanceof LoginFragment);
}
但是这次它说:
However, there were other interactions with this mock:
指向 myActivity.onCreate(null)
行。
编辑 2
如果使用间谍,并在间谍 Activity 上调用 onCreate()
,像这样:
private ActivityController<MainActivity> controller;
private MainActivity activity;
private MainActivity spy;
@Before
public void setup() throws Exception {
controller = Robolectric.buildActivity(MainActivity.class);
activity = (MainActivity) controller.get();
}
@Test
public void testShowLoginWhenSessionClosed() throws Exception {
Session session = new Session(Robolectric.application);
spy = Mockito.spy(activity);
Mockito.doReturn(session).when(spy).getActiveSession();
Mockito.doReturn(true).when(spy).sessionClosed();
spy.onCreate(null);
Mockito.verify(spy).getActiveSession();
Fragment fragment = spy.getSupportFragmentManager().findFragmentById(R.id.container);
Assert.assertTrue(fragment instanceof LoginFragment);
}
然后我得到以下异常,指向行 spy.onCreate(null)
:
java.lang.IllegalStateException: System services not available to Activities before onCreate()
at android.app.Activity.getSystemService(Activity.java:4492)
at android.view.LayoutInflater.from(LayoutInflater.java:211)
at org.robolectric.shadows.ShadowActivity.getLayoutInflater(ShadowActivity.java:148)
at android.app.Activity.getLayoutInflater(Activity.java)
at org.example.MainActivityTest.testShowLoginWhenSessionClosed(MainActivityTest.java:109)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:236)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access[=18=]0(ParentRunner.java:50)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:222)
at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:158)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
你的测试有很多问题。
- 你正在创建一个间谍,但实际上并没有在你的测试中使用它。
- 在调用将导致调用该方法的代码之前,您正在尝试验证是否已调用该方法。
- 您从未调用
onCreate
,这似乎是您要测试的方法。
此外,该堆栈跟踪与您展示的代码不匹配 - 您可能 运行 源代码的旧版本。您需要清理目标目录并重建。
我正在尝试学习 Robolectric
和 Mockito
,以实现我正在为已经运行的 Android 项目创建测试。但我遇到了一些麻烦。这将使您了解我正在尝试测试的 Activity:
public class MainActivity extends FragmentActivity {
public Session session;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
session = getActiveSession();
if (session == null ) {
// ...
} else {
if (sessionClosed()) {
LoginFragment fragment = new LoginFragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.container, fragment);
ft.commit();
}
}
}
...
public Session getActiveSession() {
return Session.getActiveSession();
}
public boolean sessionClosed() {
return session.isClosed();
}
}
这段代码的作用是获取活动 Facebook
会话,并根据其状态显示不同的 Fragment
。现在我将向您展示测试 class:
@RunWith(RobolectricTestRunner.class)
public class MainActivityTest {
private ActivityController<?> controller;
private MainActivity activity;
private MainActivity spy;
@Before
public void setup() throws Exception {
controller = Robolectric.buildActivity(MainActivity.class);
activity = (MainActivity) controller.create().get();
spy = Mockito.spy(activity);
}
@Test
public void testShowLoginWhenSessionClosed() {
Session session = new Session(Robolectric.application);
Mockito.doReturn(session).when(spy).getActiveSession();
Mockito.doReturn(true).when(spy).sessionClosed();
Mockito.verify(spy).getActiveSession();
Fragment fragment = activity.getSupportFragmentManager()
.findFragmentById(R.id.container);
Assert.assertTrue(fragment instanceof LoginFragment);
}
}
如您所见,我在单独的 java 项目中使用 Robolectric 和 Mockito。当我运行测试时 class 我得到以下信息:
Wanted but not invoked:
mainActivity.getActiveSession();
-> at org.example.MainActivityTest.testShowLoginWhenSessionClosed(MainActivityTest.java:101)
Actually, there were zero interactions with this mock.
at org.example.MainActivityTest.testShowLoginWhenSessionClosed(MainActivityTest.java:101)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:236)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access[=14=]0(ParentRunner.java:50)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:222)
at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:158)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
你能帮我处理一下吗?
编辑
我摆脱了 Activity 控制器,看看手动处理生命周期是否有效,但我收到相同的 "Wanted but not invoked" 消息:
@Test
public void testShowLoginWhenSessionClosed() throws Exception {
Session session = new Session(Robolectric.application);
MainActivity myActivity = Mockito.mock(MainActivity.class);
Mockito.when(myActivity.getActiveSession()).thenReturn(session);
Mockito.when(myActivity.sessionClosed()).thenReturn(true);
myActivity.onCreate(null);
myActivity.getActiveSession(); // works only if i call it manually
Mockito.verify(myActivity).getActiveSession();
Fragment fragment = myActivity.getSupportFragmentManager()
.findFragmentById(R.id.container);
Assert.assertTrue(fragment instanceof LoginFragment);
}
但是这次它说:
However, there were other interactions with this mock:
指向 myActivity.onCreate(null)
行。
编辑 2
如果使用间谍,并在间谍 Activity 上调用 onCreate()
,像这样:
private ActivityController<MainActivity> controller;
private MainActivity activity;
private MainActivity spy;
@Before
public void setup() throws Exception {
controller = Robolectric.buildActivity(MainActivity.class);
activity = (MainActivity) controller.get();
}
@Test
public void testShowLoginWhenSessionClosed() throws Exception {
Session session = new Session(Robolectric.application);
spy = Mockito.spy(activity);
Mockito.doReturn(session).when(spy).getActiveSession();
Mockito.doReturn(true).when(spy).sessionClosed();
spy.onCreate(null);
Mockito.verify(spy).getActiveSession();
Fragment fragment = spy.getSupportFragmentManager().findFragmentById(R.id.container);
Assert.assertTrue(fragment instanceof LoginFragment);
}
然后我得到以下异常,指向行 spy.onCreate(null)
:
java.lang.IllegalStateException: System services not available to Activities before onCreate()
at android.app.Activity.getSystemService(Activity.java:4492)
at android.view.LayoutInflater.from(LayoutInflater.java:211)
at org.robolectric.shadows.ShadowActivity.getLayoutInflater(ShadowActivity.java:148)
at android.app.Activity.getLayoutInflater(Activity.java)
at org.example.MainActivityTest.testShowLoginWhenSessionClosed(MainActivityTest.java:109)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:236)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access[=18=]0(ParentRunner.java:50)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:222)
at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:158)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
你的测试有很多问题。
- 你正在创建一个间谍,但实际上并没有在你的测试中使用它。
- 在调用将导致调用该方法的代码之前,您正在尝试验证是否已调用该方法。
- 您从未调用
onCreate
,这似乎是您要测试的方法。
此外,该堆栈跟踪与您展示的代码不匹配 - 您可能 运行 源代码的旧版本。您需要清理目标目录并重建。