Robolectric测试中的Android Activity中的模拟字段

问题描述 投票:0回答:1

所以,我正在使用遗留代码,我想对其中一个更简单的屏幕进行单元测试,即登录。我没有任何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
        ...
    }
}

我试图主要根据谷歌的调查结果对我的TestClass中的指令进行重新排序,但似乎没有任何效果。据我所知,当调用getFireBaseInstanceId方法时,firebaseInstanceId不应为null,因为在setup()方法期间注入了initMocks(this)。

这适用于其他测试,但实际上没有一个组合robolectric和mockito。

EDIT1: 我把initMocks(this)作为setup()的第一行 我添加了一些System.out.println以查看发生了什么,我注意到LoginActivity构造函数多次获取calles(一次用于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();
    }

虽然可能不像我想的那样干净,但它可以完成工作,而无需更改我的生产代码。

java android unit-testing mockito robolectric
1个回答
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();
© www.soinside.com 2019 - 2024. All rights reserved.