【问题标题】:How to mock method before activity is created?如何在创建活动之前模拟方法?
【发布时间】:2015-11-02 18:55:22
【问题描述】:

我有一个活动

public class MyActivity extends ActionBarActivity {

    public int i;

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        i = getSomeInt();
    }

    protected int getSomeInt() {
        return 1; // here can be an api-request
    }

}

我想用 robolectric 3.0mockito 对其进行测试。

但我需要模拟 getSomeInt() 方法。

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class)
public class MyActivityTest {

    private MyActivity mActivity;

    @Before
    public void setUp() {

        mActivity = spy(Robolectric.buildActivity(MyActivity.class).create().get());
        doReturn(2).when(mActivity).getSomeInt(); //but it is already after onCreate!

    }

    @Test
    public void testGetInt() {
        assertEquals(2, mActivity.i); //error
    }
}

是否可以通过创建活动来使用已经模拟的方法?

编辑

我试过了

@Before
public void setUp() {
    ActivityController<MyActivity> co = Robolectric.buildActivity(MyActivity.class);
    mActivity = spy(co.get());
    doReturn(2).when(mActivity).getSomeInt();
    co.create();
}

但我似乎,onCreate 没有被mActivity 调用

assertEquals(2, mActivity.i); //给出结果:

java.lang.AssertionError: 
Expected :2
Actual   :0

感谢 Eugen 的考虑,它不起作用,因为 create 调用控制器,该控制器使用未被监视的活动进行操作

【问题讨论】:

  • 您是否考虑将getsomeInt() 呼叫转移到onResume

标签: android unit-testing mocking mockito robolectric


【解决方案1】:

Mockito 只模拟一个对象。但不能修改ActivityController的活动引用。

所以我尝试隔离函数并在创建之前将其传递给活动。

四个步骤:

  1. 将函数隔离为新类的成员

    public class SomeInt{
        public int get() {
            return 1; // here can be an api-request
        }
    }
    
  2. 通过MyActivity中的对象使用函数

    public class MyActivity extends ActionBarActivity {
    
        SomeInt someInt;
    
        @Override
        protected void onCreate(final Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            i = someInt.get();
        }
    }
    
    1. 制作一个API来设置对象someInt在测试中

      • 使用ShadowActivity -- 我推荐这个,将代码和测试分开

        @Implements(MyActivity.class)
        public class ShadowMyActivity extends ShadowActivity
        {
            @RealObject
            private MyActivity myActivity;
        
            @Implementation
            public void setForMockito(SomeInt someint)
            {
                myActivity.someint = someint;
            }
        }
        
      • 或者让对象公开

        public SomeInt someInt;

      • 或为MyActivity中的对象创建一个公共设置器

    2. 模拟测试

      • 如果使用ShadowActivity

        @Config(constants = BuildConfig.class shadows = ShadowMyActivity.class)
        Class TestMyActivity {
        
            @Before
            public void setUp()
            {
                SomeInt someIntMock = mock(SomeInt.class);
        
                ActivityController<MyActivity> co = Robolectric.buildActivity(MyActivity.class);
        
                mActivity.setForMockito(someIntMock);
        
                doReturn(2).when(someIntMock).get();
        
                co.create();
        
                // verify here or in tearDown
            }
        
            ...
        }
        

【讨论】:

    【解决方案2】:

    我认为这是不可能的。我试图在测试中创建 Activity,对其进行监视,然后使用该间谍创建一个控制器,但我无法让它工作,所以我无法想象你是如何做到的。

    话虽如此,但这并不意味着您的根本问题没有解决方案,只是监视活动不是解决问题的方法。我建议您问第二个问题,在其中具体解释您要实现的目标(例如,在测试中模拟网络组件),您可能会得到一些替代解决方案来帮助您实现目标。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-10
      • 1970-01-01
      • 2021-08-23
      相关资源
      最近更新 更多