2011-03-11 24 views
10

我已經實現了Content Provider,它從安裝在網絡上的服務中檢索數據。 內容提供商需要從共享偏好所需的參數(用戶憑證,應用程序名稱等)從單元測試中調用getSharedPreferences()時UnsupportedOperationException

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,我應該使用其他方法嗎?

回答

6

你必須注入,使用AndroidTestCase.setContext()延伸MockContext和覆蓋至少getPackageName()getSharedPreferences()一個Context

不幸的是,不可能將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); 
     } 
    } 

} 
+0

注射上下文是一個主要問題。我沒有找到注入Context的方法 – Glaxalg 2011-03-15 22:40:09

1

只是延長AndroidTestCase代替ProviderTestCase2和使用getContext()

0

你可以重構你的內容提供者共享偏好的所有使用推入一個MyHelper類。

默認MyHelper實現可以使用共享首選項,就像您現在正在使用它並通過getters返回所需的值。

在測試過程中,您可以注入一個特殊的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()); 
} 
相關問題