2013-04-23 32 views
6

Tôi đã đọc rất nhiều liên kết từ đây, blog github và robolectric nhưng không thể tìm thấy giải pháp làm việc nào (đã sử dụng Robolectric 2.0 alpha 2).Robolectric: Làm thế nào tôi có thể kiểm tra một hoạt động có chứa một SherlockFragment?

CẬP NHẬT: Sự cố cũng xảy ra ngay cả khi chúng tôi thay thế SherlockFragment cho android.support.v4.app.Fragment.

tôi đã có thể thử nghiệm một SherlockFragmentActivity sau khi làm theo tip này, nhưng khi tôi thêm đoạn này, đó là một SherlockFragment, để hoạt động xml của tôi:

<fragment 
    android:name="com.marcelopazzo.fragmentapplication.ExampleFragment" 
    android:id="@+id/example_fragment" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" /> 

Lớp SherlockFragment:

public class ExampleFragment extends SherlockFragment { 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     return inflater.inflate(R.layout.example_fragment, container, false); 
    } 
} 

Và đây là bố cục đang được tăng thêm bởi đoạn:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical" > 

    <TextView 
     android:id="@+id/hello_again" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="@string/hello_again" /> 

</LinearLayout> 

tôi nhận được lỗi sau:

java.lang.NullPointerException 
    at org.robolectric.shadows.ShadowViewGroup.addView(ShadowViewGroup.java:69) 
    at android.view.ViewGroup.addView(ViewGroup.java) 
    at org.robolectric.res.builder.LayoutBuilder.constructFragment(LayoutBuilder.java:150) 
    at org.robolectric.res.builder.LayoutBuilder.create(LayoutBuilder.java:104) 
    at org.robolectric.res.builder.LayoutBuilder.doInflate(LayoutBuilder.java:42) 
    at org.robolectric.res.builder.LayoutBuilder.doInflate(LayoutBuilder.java:45) 
    at org.robolectric.res.builder.LayoutBuilder.inflateView(LayoutBuilder.java:62) 
    at org.robolectric.shadows.ShadowLayoutInflater.inflate(ShadowLayoutInflater.java:50) 
    at org.robolectric.shadows.ShadowLayoutInflater.inflate(ShadowLayoutInflater.java:55) 
    at android.view.LayoutInflater.inflate(LayoutInflater.java) 
    at com.squareup.test.ActionBarSherlockRobolectric.setContentView(ActionBarSherlockRobolectric.java:38) 
    at com.actionbarsherlock.app.SherlockFragmentActivity.setContentView(SherlockFragmentActivity.java:262) 
    at com.marcelopazzo.fragmentapplication.MainActivity.onCreate(MainActivity.java:13) 
    at com.marcelopazzo.fragmentapplication.MainActivityTest.setUp(MainActivityTest.java:33) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27) 
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:110) 
    at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:234) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:133) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:114) 
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:188) 
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:166) 
    at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:86) 
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:101) 
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:74) 

Đây là lớp học thử nghiệm mà tôi đang sử dụng:

@RunWith(RobolectricTestRunner.class) 
public class MainActivityTest { 

    private MainActivity activity; 
    private TextView textView; 

    public static final String GREETINGS = "Hello world!"; 

    @Before 
    public void setUp() { 

     ActionBarSherlock.registerImplementation(ActionBarSherlockRobolectric.class); 
     ActionBarSherlock.unregisterImplementation(ActionBarSherlockNative.class); 
     ActionBarSherlock.unregisterImplementation(ActionBarSherlockCompat.class); 

     activity = new MainActivity(); 
     activity.onCreate(null); 

     textView = (TextView) activity.findViewById(R.id.hello); 
    } 

    @Test 
    public void shouldGreet() { 
     assertEquals(GREETINGS, textView.getText()); 
    } 
} 

Ứng dụng này đang làm việc tốt trên các thiết bị.

Tôi thiếu gì ở đây?

ps: Các mã nguồn đầy đủ có sẵn trên github

Edit: Ngoài ra thử nghiệm với mã từ vuông/master (2.0 alpha 3 vuông 5) chi nhánh và có cùng một vấn đề. Kiểm tra LayoutBuilder.constructFragment, tôi nghĩ rằng vấn đề là activity.getSupportFragmentManager().beginTransaction().add(fragment, tag).commit() không hoạt động với SherlockFragment, vì vậy fragment.getView() sẽ trả về giá trị rỗng.

Tôi không chắc chắn liệu mình có thể làm bất cứ điều gì để sửa lỗi này không ... Tôi đã kiểm tra xem tôi có thể sửa nó trên mặt của robolectric hay không, vui lòng cho tôi biết nếu có ai có mẹo này.

Trả lời

7

Bạn có thể thử sử dụng ActivityController mới Robolectric 2.0, mà sửa chữa một số vấn đề lịch/trật tự-of-hoạt động thường nảy sinh.

MainActivity activity = Robolectric.buildActivity(MainActivity.class) 
            .create().get(); 

Nó sắp xếp cho looper chính tạm thời bị tạm dừng trong khi gọi hàm onCreate().

+1

Hi @Xian, nhờ trả lời. Tôi vừa thử nghiệm với 2.0-rc1 và 2.0-rc2-SNAPSHOT. Vẫn nhận được một NPE java.lang.NullPointerException: null \t tại android.view.ViewGroup.addView (ViewGroup.java:3187) \t tại android.view.ViewGroup.addView (ViewGroup.java:3170) \t tại org .robolectric.res.builder.LayoutBuilder.constructFragment (LayoutBuilder.java:150) – marcelopazzo

+0

Đã đẩy mã cập nhật lên [github] (https://github.com/marcelopazzo/RobolectricSample). Ngoài ra phát hiện ra rằng điều này không liên quan đến ActionBarSherlock, tôi nhận được các lỗi tương tự bằng cách sử dụng android.support.v4.app.Fragment. – marcelopazzo

+0

Sự cố đã được khắc phục trên robolectric 2.1 – marcelopazzo

0

Tôi không hài lòng với giải pháp này, nhưng có một cách để làm cho nó hoạt động:

Phương pháp fragment.getView() đang trở lại null vì các onCreateView từ Fragment tôi chưa từng được gọi. Nó phải được gọi theo phương thức moveToState từ android.support.v4.app.FragmentManager, nhưng không phải vì f.mFromLayout là sai.

f.mActivity = mActivity; 
f.mFragmentManager = mActivity.mFragments; 
f.mCalled = false; 
f.onAttach(mActivity); 
if (!f.mCalled) { 
    throw new SuperNotCalledException("Fragment " + f 
    + " did not call through to super.onAttach()"); 
} 
mActivity.onAttachFragment(f); 

if (!f.mRetaining) { 
    f.mCalled = false; 
    f.onCreate(f.mSavedFragmentState); 
    if (!f.mCalled) { 
     throw new SuperNotCalledException("Fragment " + f 
     + " did not call through to super.onCreate()"); 
    } 
} 
f.mRetaining = false; 
if (f.mFromLayout) { 
    // For fragments that are part of the content view 
    // layout, we need to instantiate the view immediately 
    // and the inflater will take care of adding it. 
    f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState), 
    null, f.mSavedFragmentState); 
    if (f.mView != null) { 
    f.mInnerView = f.mView; 
    f.mView = NoSaveStateFrameLayout.wrap(f.mView); 
    if (f.mHidden) f.mView.setVisibility(View.GONE); 
     f.onViewCreated(f.mView, f.mSavedFragmentState); 
    } else { 
     f.mInnerView = null; 
    } 
} 

Vì vậy, nếu bạn thêm khối mã này vào đoạn của bạn, phương pháp này sẽ hoạt động.

Field field = Fragment.class.getDeclaredField("mFromLayout"); 
field.setAccessible(true); 
field.setBoolean(this, true); 
field.setAccessible(false); 

Như tôi đã nói, không phải là giải pháp thực sự, nhưng là cách để làm cho nó hoạt động trước khi ai đó tìm được giải pháp phù hợp.

[UPDATE] Phương pháp này sẽ không làm việc với Robolectric 2.0 cuối cùng

3

Calling

Robolectric.buildActivity(YourActivityClass.class).attach().create().start().resume().get(); 

sẽ gọi phương thức Fragment.onCreateView bạn

+0

Cảm ơn mẹo. Tôi đã thử kết hợp khác nhau của các cuộc gọi ban đầu (ref: http://robolectric.org/activity-lifecycle/) và đây là thiết lập tối thiểu làm việc cho trường hợp của tôi: .create(). Visible(). Start(). Get(); Trước đây tôi chỉ sử dụng .create(). Visible(). Get() và các khung nhìn trên các đoạn không được tạo ra. Robolectric 3.0. –

Các vấn đề liên quan