gpt4 book ai didi

java - 在 Android 代码中模拟创建 AsyncTasks 和 Intents 的优雅方式

转载 作者:太空狗 更新时间:2023-10-29 16:41:18 25 4
gpt4 key购买 nike

我有一个 Android Activity ,其中有像这样的调用

final ConnectToServerAsyncTask task = new ConnectToServerAsyncTask(...);

final Intent intent = new Intent(this, SomeActivity.class);

为了对此类进行单元测试,我需要能够模拟 ConnectToServerAsyncTaskIntent 的创建(例如使用 Mockito)。

还有比下面描述的更优雅的方法吗?

public class MainActivityOfTheApp extends Activity {
private IAsyncTaskFactory asyncTaskFactory = new AsyncTaskFactory();
private IIntentFactory intentFactory = new IntentFactory();

public void setAsyncTaskFactory(final IAsyncTaskFactory aFactory)
{
asyncTaskFactory = aFactory;
}

public void setIntentFactory(final IIntentFactory aFactory)
{
intentFactory = aFactory;
}

@Override
protected void onResume() {
...
final ConnectToServerAsyncTask task = asyncTaskFactory.create(...);
...

final Intent intent = intentFactory.create(this, OtherActivity.class);
...
}
}

在单元测试中,我会创建一个 MainActivityOfTheApp 实例,然后使用 setAsyncTaskFactorysetIntentFactory 注入(inject)模拟。

最佳答案

PowerMock

您可以使用 PowerMock 模拟构造函数.

所以在你的情况下,测试看起来像这样:

@RunWith(PowerMockRunner.class)
@PrepareForTest(MainActivityOfTheApp.class)
public class MainActivityOfTheAppTest{
private AsyncTaskFactory asyncTaskFactory;
private IntentFactory intentFactory;
private MainActivityOfTheApp mainActivityOfTheApp;

@Before
public void prepare() {
asyncTaskFactory = PowerMockito.mock(AsyncTaskFactory.class);
intentFactory = PowerMockito.mock(IntentFactory.class);
PowerMockito.whenNew(AsyncTaskFactory.class).withNoArguments().thenReturn(asyncTaskFactory);
PowerMockito.whenNew(IntentFactory.class).withNoArguments().thenReturn(intentFactory);
mainActivityOfTheApp = new MainActivityOfTheApp();
}

@Test
public void doTest() {
//mainActivityOfTheApp has the mocks in final field inside, no need for the setters.
}
}

我必须指出,PowerMock 功能强大,但在复杂的类加载(例如 OSGI 环境)或代码覆盖工具(例如 jacoco)方面经常存在问题。它通常有效,但我已经浪费了一些时间。

没有PowerMock

第二种可能性是创建package private (没有修饰符。为什么不是 protected 或 public?参见 What's wrong with overridable method calls in constructors? )方法,它调用构造函数是这样的:

public class MainActivityOfTheApp extends Activity {
private final IAsyncTaskFactory asyncTaskFactory = constructAsyncTaskFactory();
private final IIntentFactory intentFactory = constructIntentFactory();

IAsyncTaskFactory constructAsyncTaskFactory()
{
return new AsyncTaskFactory();
}

IIntentFactory constructIntentFactory()
{
return new IntentFactory();
}
...
}

然后在你的单元测试中(测试必须与被测试的类在同一个包中!)你覆盖 construct*() 方法:

public class MainActivityOfTheAppTest{
private AsyncTaskFactory asyncTaskFactory;
private IntentFactory intentFactory;
private MainActivityOfTheApp mainActivityOfTheApp;

@Before
public void prepare() {
asyncTaskFactory = mock(AsyncTaskFactory.class);
intentFactory = mock(IntentFactory.class);
mainActivityOfTheApp = new HackedMainActivityOfTheApp();
}

@Test
public void doTest() {
//mainActivityOfTheApp has the mocks in final field inside, no need for the setters.
}

private class HackedMainActivityOfTheApp extends MainActivityOfTheApp {
IAsyncTaskFactory constructAsyncTaskFactory()
{
return asyncTaskFactory;
}

IIntentFactory constructIntentFactory()
{
return intentFactory;
}
}
}

如果您对包含 MainActivityOfTheApp 的 jar 进行签名,则可以保护构造*方法。参见 https://stackoverflow.com/a/968612/337621 :

Also, patches are harder (you have to re-sign the jar), class-patches are impossible (all classes in a single package must have the same signature source) and splitting jars becomes a chore.

关于java - 在 Android 代码中模拟创建 AsyncTasks 和 Intents 的优雅方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17389466/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com