如何在每个unit testing中获取我的Application类的新实例?

我有一个Android应用程序,它具有inheritance自Application MyApplication类。

我创建了一些使用@RunWith(AndroidJUnit4.class)运行的unit testing。 如果我单独运行每个测试,他们都会通过。 如果我一起运行 – 第一个通过然后(其中一些)其他人失败。

问题是,似乎只创建了一个MyApplication实例,然后将其保留并用于导致失败的所有测试,因为MyApplication的状态必须只初始化一次。

有没有办法运行unit testing(androidTest)所以应用程序重新启动每个测试? 我不在乎它是否会很慢(例如每次都必须重新安装应用程序)我只想让测试彼此独立运行。

unit testing的实际代码如下(根据@Zinc的要求):

 @RunWith(AndroidJUnit4.class) public class AutoLogin_ActMainTest { @Rule public ActivityTestRule mActivityRule = new ActivityTestRule( ActMain.class) { @Override protected void beforeActivityLaunched() { super.beforeActivityLaunched(); MyTestApp app = (MyTestApp) InstrumentationRegistry.getInstrumentation().getTargetContext().getApplicationContext(); DependencyInjector.reset(); app.reset(); FakeUnitDaggerModule fudm = new FakeUnitDaggerModule(); Session session = new SessionImpl(new TimeProviderImpl()); fudm.setResMain(new ResMainTest(session)); FakeAppPrefs appPrefs = new FakeAppPrefs(); FakeLoginPrefs loginPrefs = new FakeLoginPrefs(); CurrentUserHolder currentUserHolder = new CurrentUserHolder(); FakeComponent inj = DaggerFakeComponent.builder(). fakeMyAppDaggerModule(new FakeMyAppDaggerModule(app, appPrefs, loginPrefs, currentUserHolder)). appInfoDaggerModule(new AppInfoDaggerModule("1")). fakeSessionDaggerModule(new FakeSessionDaggerModule(session)). fakeExchangeDaggerModule(new FakeExchangeDaggerModule("https://test.com")). fakeUnitDaggerModule(fudm). build(); DependencyInjector.init(inj); DependencyInjector.getInstance().inject(app); app.onStart(); } }; @Test public void testAutoLogin() { ElapsedTimeIdlingResource idlingResource = new ElapsedTimeIdlingResource(500); Espresso.registerIdlingResources(idlingResource); idlingResource.startWaiting(); onView(ViewMatchers.withId(R.id.tv_logged_in_as)).check(matches(isDisplayed())); Espresso.unregisterIdlingResources(idlingResource); } } 

问题是,似乎只创建了一个MyApplication实例,然后将其保留并用于导致失败的所有测试,因为MyApplication中的状态必须只初始化一次。

恕我直言,这是应用程序中的一个错误,应该修复。 对于许多真正的业务逻辑, Application是一个不合适的位置(尽管它可以用于初始化崩溃报告库, StrictMode等)。 其他所有东西都应该单独测试,可以直接测试,通过模拟,dependency injection等。

话虽如此,有时问题不在于您控制的代码中,而是来自库或框架的代码。

有没有办法运行unit testing(androidTest)所以应用程序重新启动每个测试?

现在,是的,虽然当时没有问这个问题。 Android Test Orchestrator (ATO)以测试执行速度为代价,更好地隔离每个测试。

您需要重构您的应用程序,以便控制状态的任何代码都不会绑定到应用程序类,而是绑定到另一个对象。 然后,您可以重置该部分或模拟它,而无需关心应用程序类的持久性。 优选地,这使用一些forms依赖性注入来完成。

我不太确定你的问题。 但您可以使用ApplicationTestCase。 就像是:

 public class MyApplicationTest extends ApplicationTestCase { public void test1() { createApplication(); ... test here ... terminateApplication(); } public void test2() { createApplication(); ... test here ... terminateApplication(); } } 

参考: https : //developer.android.com/reference/android/test/ApplicationTestCase.html

  public class TestApplication extends Application { @Override public void onCreate() { super.onCreate(); // Sdk.terminate(); - If you specify TestApplication as an // application class in AndroidManifest, // you'll have to uncomment this(due to issue with test runner) Sdk.initialize(); } @Override public void onTerminate() { super.onTerminate(); Sdk.terminate(); } } 

Sdk课

  public class Sdk { private static Sdk sInstance; private void Sdk(){ } public static Sdk getInstance() throws RuntimeException { if (sInstance == null) { throw new RuntimeException(); } return sInstance; } public static void terminate() { sInstance = null; } public static void initialize() { if (sInstance == null) { sInstance = new Sdk(); //save some information according to what is on the default configurations } else { throw new RuntimeException("Method was already initialized"); } }} 

测试:

  public class MyApplicationTest extends ApplicationTestCase { public MyApplicationTest() { super(TestApplication.class); } public void testMultiplicationTests() { createApplication(); int answer = 42; assertEquals(42, answer); terminateApplication(); } public void testDefaultSettings() { createApplication(); assertNotNull(Sdk.getInstance()); terminateApplication(); }}