因此,我正在使用旧代码,我想对一个简单的屏幕之一即登录进行单元测试。 我没有任何DI框架。
我使用robolectric 4.0.1和mockito 1.10.19
当前,由于我尝试模拟的对象上的NullPointer导致我的测试失败:
TestClass
@RunWith(RobolectricTestRunner.class)
public class LoginActivityTest {
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@Mock
FirebaseInstanceId firebaseInstanceId;
@InjectMocks
private LoginActivity activity;
@Before
public void setup() {
when(firebaseInstanceId.getToken()).thenReturn("mockToken");
ActivityController<LoginActivity> activityController = Robolectric.buildActivity(LoginActivity.class);
activity = activityController.get();
initMocks(this);
activityController.create();
}
@Test
public void checkThatLoginButtonExists() {
// does not reach this point
Button btn = (Button) activity.findViewById(R.id.button_login);
assertNotNull("Button exisits", btn);
}
}
正在测试的课程
public class LoginActivity extends FragmentActivity {
private Button mBtnLogin;
public LoginActivity() {
//default constructor
}
private FirebaseInstanceId firebaseInstanceId;
private FirebaseInstanceId getFirebaseInstanceId(){
if (firebaseInstanceId == null){
firebaseInstanceId = FirebaseInstanceId.getInstance();
}
return firebaseInstanceId;
}
private void initViews() {
...
mBtnLogin = (Button) findViewById(R.id.button_login);
...
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login_layout);
...
initViews();
...
registerNotification();
}
private void registerNotification() {
String newFcmToken = getFirebaseInstanceId().getToken(); // fails here
...
}
}
我主要尝试根据Google的发现对TestClass中的指令进行重新排序,但似乎无济于事。
据我了解,调用getFireBaseInstanceId
方法时firebaseInstanceId不应为null,因为它是在setup()
方法中注入initMocks(this)的。
这可用于其他测试,但实际上没有一个结合了robolectric和Mockito。
EDIT1:
我已经将initMocks(this)作为setup()的第一行
我添加了一些System.out.println以查看会发生什么,并且我注意到LoginActivity构造函数多次被调用(对于initMocks,一次,对于Robolectric.buildActivity)
EDIT2: 我已将测试类中的设置更改为如下
private void setMyOwnMock(String fieldName, Object inClass, Object mock ){
Field declaredField;
try {
declaredField = inClass.getClass().getDeclaredField(fieldName);
declaredField.setAccessible(true);
declaredField.set(inClass, firebaseInstanceId);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
@Before
public void setup() {
ActivityController<LoginActivity> activityController = Robolectric.buildActivity(LoginActivity.class);
activity = activityController.get();
setMyOwnMock("firebaseInstanceId", activity, firebaseInstanceId);
when(firebaseInstanceId.getToken()).thenReturn("mockToken");
// System.out.println(activity.firebaseInstanceId == null);
activityController.create();
}
虽然可能不尽如人意,但无需更改生产代码即可完成工作。
答案 0 :(得分:0)
在这种情况下,注入和自动创建将不起作用。
@InjectMocks
private LoginActivity activity;
在设置中被以下方式覆盖:
ActivityController<LoginActivity> activityController =
Robolectric.buildActivity(LoginActivity.class);
activity = activityController.get();
因此,您需要手动设置该对象的FirebaseInstanceId
实例变量:
@Before
public void setup() {
initMocks(this);
when(firebaseInstanceId.getToken()).thenReturn("mockToken");
ActivityController<LoginActivity> activityController =
Robolectric.buildActivity(LoginActivity.class);
activity = activityController.get();
activity.setFirebaseInstanceId(firebaseInstanceId);
activityController.create();