AndroidTesting: Mock Context

本文介绍了 Android 开发中使用 MockContext 进行单元测试的方法,包括如何创建和使用 MockContext 来隔离文件和数据库操作,确保测试独立性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://docs.google.com/View?id=ddwc44gs_21737cgtvfj

AndroidTesting: Mock Context

 

This document can be read in Google Docs (http://docs.google.com/View?id=ddwc44gs_21737cgtvfj), cut and paste link if you have problems accessing it.

 

Continuing with our Android Testing series, we take a short detour before we proceed to create more unit and functional tests.
We have visited Mock Objects before and evaluated our Test Driven Development purism and the concerns about not using real objects, but this is another discussion.
Sometimes, introducing mock objects in our tests is recommended, desirable, useful or even unavoidable.
Android SDK provides some classes to help us in this quest in the package android.test.mock:

mock context overview

Mock Context class implements all methods in a non-functional way and throw UnsopportedOperationException.
This can be used to inject other dependencies, mocks, or monitors into the classes under testing. A fine control can be obtained extending this class.

Extend this class to provide your desired behaviour overriding the correspondent methods.

mocking file and database operations

In some cases, all we need is to be able to mock the file and database operations. For example, if we are testing the application on a real device perhaps we don't want to affect existing files during our tests.
Such cases can take advantage of another class that is not part of the android.test.mock package but of android.test instead, that is RenamingDelegatingContext. I think it belongs to the former but it is in the parent package for apparently no reason.
This class let us mock operations and files and databases are prefixed by a prefix that is specified in the constructor. All other operations are delegated to the delegating Context that you must specify in the constructor too.

Suppose our Activity under test uses some files we want to control in some way, maybe introducing specialised content to drive our tests and we don't want or we can't use the real files, in this case we create a RenamingDelegatingContext specifying a pefix, we provide that files, and our unchanged Activity will use them.

Download:
Source code of the main and test projects can be downloaded from http://sites.codtech.com/android/Home/source-code

Our Activity under test, MockContextExamplesActivity, displays the content of a file inside a TextView, what we intend is to be able to display different content during a test than during normal operation of the Activity.
MockContextExamplesActivity.java
A very simple Activity. Shows the content of the file myfile.txt inside a TextView.

package com.codtech.android.training.mockcontext.examples;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.widget.TextView;

public class MockContextExamplesActivity extends Activity {
    public final static String FILE_NAME = "myfile.txt";
    
    private TextView tv;
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        tv = (TextView) findViewById(R.id.TextView);
        final byte[] buffer = new byte[1024];
        
        try {
            final FileInputStream fis = openFileInput(FILE_NAME);
            final int n = fis.read(buffer);
            tv.setText(new String(buffer, 0, n-1));
        } catch (Exception e) {
            tv.setText(e.toString());
            tv.setTextColor(Color.RED);
        }
    }
    
    public String getText() {
        return tv.getText().toString();
    }
}

MyMockContext.java
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

import android.content.Context;
import android.test.RenamingDelegatingContext;
import android.util.Log;


/**
 * @author diego
 *
 */
public class MyMockContext extends RenamingDelegatingContext {
    private static final String TAG = "MyMockContext";
    
    private static final String MOCK_FILE_PREFIX = "test.";


    /**
     * @param context
     * @param filePrefix
     */
    public MyMockContext(Context context) {
        super(context, MOCK_FILE_PREFIX);
        makeExistingFilesAndDbsAccessible();
    }

    /* (non-Javadoc)
     * @see android.test.RenamingDelegatingContext#openFileInput(java.lang.String)
     */
    @Override
    public FileInputStream openFileInput(String name)
            throws FileNotFoundException {
        Log.d(TAG, "actual location of " + name +
            " is " + getFileStreamPath(name));
        return super.openFileInput(name);
    }

    /* (non-Javadoc)
     * @see android.test.RenamingDelegatingContext#openFileOutput(java.lang.String, int)
     */
    @Override
    public FileOutputStream openFileOutput(String name, int mode)
            throws FileNotFoundException {
        Log.d(TAG, "actual location of " + name +
            " is " + getFileStreamPath(name));
        return super.openFileOutput(name, mode);
    }
}

test.myfile.txt
We also need to provide at least the text file containing the sample text.
The directory where these files are located is created during package installation, so you may want to wait till you install the package for the first time to run this command.
Notice that we are using a "test." prefix in this file creation as we did in our MyMockContext class.
To do this just run this command:

diego@bruce:/~$ adb shell echo "This is sample text" /
   /> /data/data/com.codtech.android.training.mockcontext.examples/files/test.myfile.txt

Remember to change package name if you are using a different one.

If you also want to create some real context to be displayed by the Activity use this command:

diego@bruce:/~$ adb shell echo "This is REAL text" /
   /> /data/data/com.codtech.android.training.mockcontext.examples/files/myfile.txt

Notice that here there's no "test." prefix because it's the real file.

MockContextExamplesTest.java
Now when we create some tests we can use this mock context.

import android.content.Context;
import android.content.Intent;
import android.test.ActivityUnitTestCase;

import com.codtech.android.training.mockcontext.examples.MockContextExamplesActivity;

/**
 * @author diego
 *
 */
public class MockContextExamplesTests extends ActivityUnitTestCase<MockContextExamplesActivity> {

    public MockContextExamplesTests() {
        super(MockContextExamplesActivity.class);
    }

    /**
     * @throws java.lang.Exception
     */
    protected void setUp() throws Exception {
    }

    /**
     * @throws java.lang.Exception
     */
    protected void tearDown() throws Exception {
    }

    public void testSampleTextDisplayed() {
        // mock context
        Context mockContext = new MyMockContext(getInstrumentation().getTargetContext());
        setActivityContext(mockContext);
        startActivity(new Intent(), null, null);
        final MockContextExamplesActivity activity = getActivity();
        assertNotNull(activity);
        assertEquals("This is sample text", activity.getText());
    }
    
    public void testRealTextDisplayed() {
        // real context
        setActivityContext(getInstrumentation().getTargetContext());
        startActivity(new Intent(), null, null);
        final MockContextExamplesActivity activity = getActivity();
        assertNotNull(activity);
        assertFalse("This is sample text".equals(activity.getText()));
    }
}


Conclusion

Though this is an oversimplified example it shows the most important concepts behind Mock Contexts and the way you can use Delegating Context to isolate your Activity from other parts of the system like the filesystem in this case.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值