是否可以在单元测试下模拟 android 服务? [英] Is it possible to mock android services under unit tests?

查看:26
本文介绍了是否可以在单元测试下模拟 android 服务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为我的 android 应用程序编写单元测试,并且我想模拟我的服务类.我想测试服务中的一些错误行为,例如连接错误或找不到文件.

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.

为了简化我的问题,我启动了一个新的 Android 项目并创建了一个 Activity 和一个服务类:

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);
    }

}

我用这个单元类创建了一个新的 Android 测试项目:

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));
    }
}

当我运行单元测试时,前提条件和更改按钮测试都很好.例如,我想做的是创建一个 MyServiceMock 并覆盖 MyService.getNewString 以返回其他值,并在测试中模拟此对象.

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.

像这样:

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!";
    }
}

这可能吗?

推荐答案

是的,这是可能的,我认为上面的 MyServiceMock.java 示例也是一种替代方案.

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.

我对 Mockito 有一些经验.

您可以模拟 MyService 类并指定在调用 getNewString 方法时返回一个字符串这是新值!".

You can just mock the MyService class and specify that when the getNewString method is called, return a string "This is the new value!".

MyService myServiceMock = Mockito.mock(MyService.class);

Mockito.doReturn("This is the new value!").when(myServiceMock).getNewString();

您还可以使用 Mockito.doThrow() 方法在调用模拟方法时抛出异常:

You can also use the Mockito.doThrow() method to throw an exception when a mock method is called:

Mockito.doThrow(new RuntimeException()).when(mockedList).clear();

//following throws RuntimeException:
mockedList.clear();

这篇关于是否可以在单元测试下模拟 android 服务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆