【问题标题】:UnsupportedOperationException while calling getSharedPreferences() from unit test从单元测试调用 getSharedPreferences() 时出现 UnsupportedOperationException
【发布时间】:2011-03-11 00:32:25
【问题描述】:

我已经实现了从安装在网络上的服务中检索数据的内容提供程序。 内容提供者从共享偏好中获取所需参数(用户凭据、应用程序名称等)

SharedPreferences settings = getContext().getSharedPreferences(NET_PREFS, 0);

我对此内容提供者使用单元测试:


public class ResearchProviderTest extends ProviderTestCase2<MyProvider>{

    public ResearchProviderTest() {     
        super(MyProvider.class, MyProvider.CONTENT_AUTHORITY);
    }

    public void testInsert() {

        ContentValues values = new ContentValues();        
        values.put(QueryFields.FIELD_QUERY_TEXT, "query" );

        Uri newUri = getMockContentResolver().insert(MyProvider.CONTENT_URI, values);

        Cursor readMessagesCursor = getMockContentResolver().query(
                newUri ,
                        new String[] { FIELD_SR_TITLE }, 
                        null, null, null );
        assertTrue("The cursor should contain some entries", readMessagesCursor.moveToFirst());
    }
}

在执行单元测试期间。抛出异常:


java.lang.UnsupportedOperationException
   at android.test.mock.MockContext.getSharedPreferences(MockContext.java:127)
   at android.content.ContextWrapper.getSharedPreferences(ContextWrapper.java:146)
   at android.content.ContextWrapper.getSharedPreferences(ContextWrapper.java:146)
   at com.company.mobile.android.net.RemoteExecutor.retrieveCredentials(RemoteExecutor.java:171)
   at com.company.mobile.android.net.service.Adapter.executeSearch(Adapter.java:33)
   at com.company.mobile.android.provider.MyProvider.insert(MyProvider.java:167)
   at android.content.ContentProvider$Transport.insert(ContentProvider.java:174)
   ...

有人知道如何将共享首选项传递给 MockContext 吗?如果在测试 Content Provider 期间需要 Context,我应该使用其他方法吗?

【问题讨论】:

    标签: android android-contentprovider


    【解决方案1】:

    您必须注入一个Context,它使用AndroidTestCase.setContext() 扩展MockContext,并至少覆盖getPackageName()getSharedPreferences()

    不幸的是,无法将MockContext 注入ProviderTestCase2,因为不支持 setContext()。那么,解决办法就是重写setUp(),不调用super方法。

    package com.example.aatg.ps.test;
    
    import android.test.ProviderTestCase2;
    
    import com.example.aatg.ps.ProviderSample;
    
    public class ProviderSampleTests extends ProviderTestCase2<ProviderSample> {
    
        private ResolverRenamingMockContext mProviderContext;
        private Class<ProviderSample> mProviderClass;
        private ProviderSample mProvider;
        private String mProviderAuthority;
    
        public ProviderSampleTests() {
            super(ProviderSample.class, ProviderSample.AUTHORITY);
            setName("ProviderSampleTests");
            mProviderClass = ProviderSample.class;
            mProviderAuthority = ProviderSample.AUTHORITY;
        }
    
        @Override
        protected void setUp() throws Exception {
             // We should not invoke super.setUp() here to avoid the UnsupportedOperationException.
            //super.setUp();
    
            // This is needed to support getSharedPreferences() in ProviderSample.onCreate()
            mProviderContext = new ResolverRenamingMockContext(getContext());
            mProvider = mProviderClass.newInstance();
            assertNotNull(mProvider);
            mProvider.attachInfo(mProviderContext, null);
            mProviderContext.addProvider(mProviderAuthority, mProvider);
        }
    
    
        @Override
        public ProviderSample getProvider() {
            return mProvider;
        }
    
        protected void tearDown() throws Exception {
            super.tearDown();
        }
    
        public void testProviderSampleCreation() {
            ProviderSample provider = getProvider();
            assertNotNull(provider);
        }
    }
    

    这是ResolverRenamingMockContext

    package com.example.aatg.ps.test;
    
    import java.io.File;
    
    import android.content.ContentProvider;
    import android.content.Context;
    import android.content.SharedPreferences;
    import android.content.res.Resources;
    import android.test.IsolatedContext;
    import android.test.mock.MockContentResolver;
    import android.test.mock.MockContext;
    
    /**
     * @author diego
     *
     */
    public class ResolverRenamingMockContext extends IsolatedContext {
    
        /**
         * The renaming prefix.
         */
        private static final String PREFIX = "test.";
    
    
        /**
         * The resolver.
         */
        private static final MockContentResolver RESOLVER = new MockContentResolver();
    
        /**
         * Constructor.
         * @param context 
         */
        public ResolverRenamingMockContext(Context context) {
            super(RESOLVER, new DelegatedMockContext(context));
        }
    
        public MockContentResolver getResolver() {
            return RESOLVER;
        }
    
        public void addProvider(String name, ContentProvider provider) {
            RESOLVER.addProvider(name, provider);
        }
    
        /**
         * The DelegatedMockContext.
         *
         */
        private static class DelegatedMockContext extends MockContext {
    
            private Context mDelegatedContext;
    
            public DelegatedMockContext(Context context) {
                mDelegatedContext = context;
            }
    
            @Override
            public SharedPreferences getSharedPreferences(String name, int mode) {
                return mDelegatedContext.getSharedPreferences(PREFIX + name, mode);
            }
        }
    
    }
    

    【讨论】:

    • 注入上下文是一个主要问题。我没有找到注入上下文的方法
    【解决方案2】:

    只需扩展 AndroidTestCase 而不是 ProviderTestCase2 并使用 getContext()

    【讨论】:

      【解决方案3】:

      您可以重构您的 Content Provider 以将 Shared Preferences 的所有使用推送到 MyHelper 类中。

      默认的MyHelper 实现可以像您现在使用的一样使用共享首选项,并通过getter 返回您需要的值。

      在测试期间,您可以注入一个特殊的MyHelper 实现,它不使用共享首选项。也许它被称为 TestingHelper 它只是返回测试定义的常量。

      例如在ResearchProviderTest:

      @Override
      protected void setUp() throws Exception {
          // set up normally
          super.setUp();
      
          // inject a special helper for testing
          MyProvider provider = (MyProvider) getProvider();
          provider.setHelper(new TestingHelper());
      }
      

      【讨论】:

        猜你喜欢
        • 2012-08-29
        • 2015-12-23
        • 2012-09-23
        • 1970-01-01
        • 1970-01-01
        • 2022-11-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多