是否可以在单元测试下模拟 android 服务?

发布于 2024-12-07 03:42:45 字数 4700 浏览 0 评论 0原文

我正在尝试为我的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一身仙ぐ女味 2024-12-14 03:42:45

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

您可以使用一些模拟框架来实现此目的。

我对 Mockito 有一些经验。

您可以模拟 MyService 类并指定在调用 getNewString 方法时返回一个字符串“This is the new value!”。

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

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

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

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

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

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!".

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

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

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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文