是否可以在单元测试下模拟 android 服务?
我正在尝试为我的 Android 应用程序编写单元测试,并且我想模拟我的服务类。我想测试服务中的一些错误行为,例如连接错误或找不到文件。
为了简化我的问题,我启动了一个新的 Android 项目并创建了一个 Activity 和一个 Service 类:
MyAndroidProjectActivity.java
package br.org.venturus.android;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.TextView;
import br.org.venturus.android.service.MyService;
public class MyAndroidProjectActivity extends Activity {
private MyService service;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
service = ((MyService.MyBinder) binder).getService();
}
public void onServiceDisconnected(ComponentName className) {
service = null;
}
};
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
{
Intent service = new Intent(this, MyService.class);
startService(service);
bindService(service, mConnection, Context.BIND_AUTO_CREATE);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// stop MyService
{
Intent svc = new Intent(this, MyService.class);
stopService(svc);
}
}
public void doChange(View view) {
TextView tv = (TextView) findViewById(R.id.tvHello);
tv.setText(service.getNewString());
}
}
MyService.java
package br.org.venturus.android.service;
import br.org.venturus.android.R;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
public class MyService extends Service {
private IBinder binder;
public MyService() {
this.binder = new MyBinder();
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
public class MyBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
public String getNewString() {
return getString(R.string.change);
}
}
我用这个创建了一个新的 Android 测试项目单元类:
MyAndroidProjectActivityTest.java
package br.org.venturus.android.test;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
import android.widget.Button;
import android.widget.TextView;
import br.org.venturus.android.MyAndroidProjectActivity;
import br.org.venturus.android.R;
public class MyAndroidProjectActivityTest extends
ActivityInstrumentationTestCase2<MyAndroidProjectActivity> {
private MyAndroidProjectActivity mActivity;
private TextView tvHello;
private Button btChange;
public MyAndroidProjectActivityTest() {
super("br.org.venturus.android", MyAndroidProjectActivity.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
// Get the activity and components
{
mActivity = this.getActivity();
tvHello = (TextView) mActivity
.findViewById(br.org.venturus.android.R.id.tvHello);
btChange = (Button) mActivity
.findViewById(br.org.venturus.android.R.id.btChange);
}
}
public void testPreconditions() {
assertNotNull(tvHello);
assertNotNull(btChange);
}
@UiThreadTest
public void testChangeButton() {
assertEquals(tvHello.getText(), getActivity().getString(R.string.hello));
btChange.performClick();
assertEquals(tvHello.getText(), getActivity()
.getString(R.string.change));
}
}
当我运行单元测试时,前提条件和更改按钮测试都很好。例如,我想要做的是创建一个 MyServiceMock 并重写 MyService.getNewString 以返回其他值,并在测试中模拟该对象。
像这样的东西:
MyServiceMock.java
package br.org.venturus.android.test.service;
import br.org.venturus.android.service.MyService;
public class MyServiceMock extends MyService {
@Override
public String getNewString() {
return "This is the new value!";
}
}
这可能吗?
I'm trying to write unit tests for my android application and I want to mock my service class. I want to test some error behaviors in the service, such as connection errors or file not found.
To simplify my question, I started a new Android Project and created an Activity and a Service class:
MyAndroidProjectActivity.java
package br.org.venturus.android;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.TextView;
import br.org.venturus.android.service.MyService;
public class MyAndroidProjectActivity extends Activity {
private MyService service;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
service = ((MyService.MyBinder) binder).getService();
}
public void onServiceDisconnected(ComponentName className) {
service = null;
}
};
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
{
Intent service = new Intent(this, MyService.class);
startService(service);
bindService(service, mConnection, Context.BIND_AUTO_CREATE);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// stop MyService
{
Intent svc = new Intent(this, MyService.class);
stopService(svc);
}
}
public void doChange(View view) {
TextView tv = (TextView) findViewById(R.id.tvHello);
tv.setText(service.getNewString());
}
}
MyService.java
package br.org.venturus.android.service;
import br.org.venturus.android.R;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
public class MyService extends Service {
private IBinder binder;
public MyService() {
this.binder = new MyBinder();
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
public class MyBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
public String getNewString() {
return getString(R.string.change);
}
}
And I created a new Android Test Project with this unit class:
MyAndroidProjectActivityTest.java
package br.org.venturus.android.test;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
import android.widget.Button;
import android.widget.TextView;
import br.org.venturus.android.MyAndroidProjectActivity;
import br.org.venturus.android.R;
public class MyAndroidProjectActivityTest extends
ActivityInstrumentationTestCase2<MyAndroidProjectActivity> {
private MyAndroidProjectActivity mActivity;
private TextView tvHello;
private Button btChange;
public MyAndroidProjectActivityTest() {
super("br.org.venturus.android", MyAndroidProjectActivity.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
// Get the activity and components
{
mActivity = this.getActivity();
tvHello = (TextView) mActivity
.findViewById(br.org.venturus.android.R.id.tvHello);
btChange = (Button) mActivity
.findViewById(br.org.venturus.android.R.id.btChange);
}
}
public void testPreconditions() {
assertNotNull(tvHello);
assertNotNull(btChange);
}
@UiThreadTest
public void testChangeButton() {
assertEquals(tvHello.getText(), getActivity().getString(R.string.hello));
btChange.performClick();
assertEquals(tvHello.getText(), getActivity()
.getString(R.string.change));
}
}
When I run the unit tests, the pre conditions and the change button tests are fine. What I want to do, for instance, is to create a MyServiceMock and override the MyService.getNewString to return other value, and mock this object in the test.
Something like this:
MyServiceMock.java
package br.org.venturus.android.test.service;
import br.org.venturus.android.service.MyService;
public class MyServiceMock extends MyService {
@Override
public String getNewString() {
return "This is the new value!";
}
}
Is that possible?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
是的,这是可能的,我认为上面的 MyServiceMock.java 示例也是一种替代方案。
您可以使用一些模拟框架来实现此目的。
我对 Mockito 有一些经验。
您可以模拟 MyService 类并指定在调用 getNewString 方法时返回一个字符串“This is the new value!”。
您还可以使用 Mockito.doThrow() 方法在调用模拟方法时抛出异常:
Yes, it's possible and I think the example of the MyServiceMock.java above is also an alternative.
There are a few mocking frameworks out there that you can use for this.
I have some experience with Mockito.
You can just mock the MyService class and specify that when the getNewString method is called, return a string "This is the new value!".
You can also use the Mockito.doThrow() method to throw an exception when a mock method is called: