【问题标题】:How to get the activity reference before its oncreate gets called during testing如何在测试期间调用 oncreate 之前获取活动引用
【发布时间】:2015-07-13 16:39:40
【问题描述】:

如何在调用 onCreate 之前获取 Activity 的引用。虽然它正在测试中。我使用 ActivityTestRule 作为 JUnit 规则。这个要求的原因是我想将 Mocks 注入到来自测试的活动中。

public class MyActivity extends Activity{

    MyComponent myComponent;

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        if(myComponent==null){
            myComponent ... //initialise dagger component
        }
        myComponent.inject(this);
        ...
    }

    public void setComponent(MyComponent comp){
        this.myComponent = comp;
    }
}

public class MyTest{

    @Rule
    public ActivityTestRule<MyActivity> intentsTestRule = new ActivityTestRule<>(MyActivity.class);


    MyComponent myFakeComponent;

    @Before                                      
    public void setUp() {                        
        MyActivity activity = intentsTestRule.getActivity();  
        activity.setComponent(myFakeComponent);
    }                                            

    @Test
    public void testMethod1(){...}
} 

【问题讨论】:

  • 你使用Dagger吗?如果是,你在哪里初始化 Dagger 的模块?

标签: android mocking android-testing android-espresso junit-rule


【解决方案1】:

根据文档,您在这里所做的事情是错误的。

@Rule
public ActivityTestRule<MyActivity> intentsTestRule = new ActivityTestRule<>(MyActivity.class);

MyComponent myFakeComponent;

@Before                                      
public void setUp() {                        
    MyActivity activity = intentsTestRule.getActivity();  
    activity.setComponent(myFakeComponent);
}              

因为,

此规则提供单个活动的功能测试。 被测活动将在每个测试之前启动 测试和 使用 @Before 注释的方法。 测试完成后终止,方法 用 After 注释完成。在测试期间 您将能够直接操作您的 Activity。

但是!

protected void beforeActivityLaunched ()

重写此方法以执行任何应该运行的代码 在您的 Activity 创建和启动之前。 在每个测试方法之前调用此方法, 包括使用@Before 注释的任何方法。

因此,如果您将 Activity 之外的 MainActivityComponent 的初始化移动到可模拟的位置,那么您将能够在创建主 Activity 之前将其修补在一起。

编辑:

另一种可能的解决方案是按照link 懒惰地启动 Activity。

@Rule
public ActivityTestRule<NoteDetailActivity> mNoteDetailActivityTestRule =
        new ActivityTestRule<>(NoteDetailActivity.class, true /* Initial touch mode  */,
                false /* Lazily launch activity */);

@Before
public void intentWithStubbedNoteId() {
   // Add a note stub to the fake service api layer.
   FakeNotesServiceApiImpl.addNotes(NOTE);

   // Lazily start the Activity from the ActivityTestRule this time to inject the start Intent
   Intent startIntent = new Intent();
   startIntent.putExtra(NoteDetailActivity.EXTRA_NOTE_ID, NOTE.getId());
   mNoteDetailActivityTestRule.launchActivity(startIntent);

   registerIdlingResource();
}

【讨论】:

  • new ActivityScenarioRule&lt;MainActivity&gt;(....class, true, false) 未定义
  • 当我发布答案时它起作用了,所以它要么在较新的版本中略有变化,要么你试图在 Kotlin 中使用 new ,它不再是一个关键字。
  • 我是 Kotlin 否认者;我应该指出我正在使用 Java。但我已经回答了我的外部问题 - 如何弃用 ActivityTestRule&lt;&gt; - 这里:stackoverflow.com/questions/63816672/…
【解决方案2】:

这是我的示例代码:

public class TestClass {

    @Rule
    public ActivityTestRule<T> activityRule = new ActivityTestRule<T>(type) {
            @Override
            protected void beforeActivityLaunched() {
                //TODO inject mocks, setup stubs etc..
            }
        };
    }

    @Before
    public void before() {
        activityRule.getActivity();
    }

    @Test
    public void myTest() {
        //...
    }


}

【讨论】:

    【解决方案3】:

    这段代码是否完整?我看不到你创建匕首图。 无论如何,我在我的代码中所做的是拥有一个名为 Injector 的静态类,它为我创建图形,并且还可以将元素注入到对象中。因此,在我的应用程序类中,我调用它来创建图表,而所有其他活动只使用现有图表。

    然后,在测试中,您可以创建一个假的测试应用程序类,以不同的方式初始化图表,或者在创建活动之前简单地重新创建调用 Injector 方法的图表。我对 ActivityTestRule 不熟悉,所以我对这个测试的生命周期帮不上什么忙。

    但只需确保在创建活动之前创建一个新图表,并让活动只使用现有图表。 活动如何访问图表?好吧,我不是很喜欢它,但我们习惯于访问应用程序类(使用显式转换)并要求它为我们注入依赖项。 Dagger 示例也是这样做的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-20
      • 1970-01-01
      • 2012-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多