Kiểm tra Chế độ xem tùy chỉnh bằng Robolectric


82

Tôi đang cố gắng chạy các bài kiểm tra đơn vị với Robolectric 2.1.1 và tôi không thể làm cho nó thổi phồng bố cục tùy chỉnh (ví dụ: các lớp ViewPagerIndicator). Giả sử đây là bố cục của tôi:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="test"
            android:id="@+id/test_test"/>

    <com.viewpagerindicator.CirclePageIndicator
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"/>

</LinearLayout>

Hãy coi đây là lớp thử nghiệm của tôi:

@RunWith(RobolectricTestRunner.class)
public class TestRoboActivityTest {
    private TestRoboActivity mActivity;

    @Before
    public void setUp() throws Exception {
        mActivity = Robolectric.buildActivity(TestRoboActivity.class).create().get();
    }

    @After
    public void tearDown() throws Exception {
        mActivity = null;
    }

    @Test
    public void testSanity() throws Exception {
        Assert.assertNotNull(mActivity);
    }
}

Thực hiện 'mvn clean test' cho kết quả

Kiểm tra bị lỗi:
testSanity (TestRoboActivityTest): Tệp XML. \ res \ layout \ test.xml dòng # -1 (xin lỗi, chưa được triển khai): Lỗi thổi phồng lớp com.viewpagerindicator.CirclePageIndicator

Thật tuyệt, có vẻ như các chế độ xem tùy chỉnh chưa được hỗ trợ. Kiểm tra dự án Robolectric mẫu trên trang web của họ , một giải pháp có thể là làm tăng bố cục từ LayoutInflater:

@RunWith(RobolectricTestRunner.class)
public class TestRoboActivityTest {
    private View mTestRoboActivityView;

    @Before
    public void setUp() throws Exception {
        mTestRoboActivityView = LayoutInflater.from(new Activity()).inflate(R.layout.test, null);
    }

    @After
    public void tearDown() throws Exception {
        mTestRoboActivityView = null;
    }

    @Test
    public void testSanity() throws Exception {
        Assert.assertNotNull(mTestRoboActivityView);
    }
}

kết quả là:

Kiểm tra bị lỗi: 
testSanity (TestRoboActivityTest): Tệp XML. \ res \ layout \ test.xml dòng # -1 (xin lỗi, chưa được triển khai): Lỗi thổi phồng lớp com.viewpagerindicator.CirclePageIndicator

Phương sách cuối cùng của tôi là cố gắng sử dụng các lớp bóng:

@Implements(CirclePageIndicator.class)
public class CirclePageIndicatorShadow implements PageIndicator {

    @Override
    @Implementation
    public void setViewPager(ViewPager view) {
        // Stub
    }

    // etc.
}

và sử dụng @Config(shadows = {CirclePageIndicatorShadow.class}). Điều này một lần nữa dẫn đến

Kiểm tra bị lỗi: 
testSanity (TestRoboActivityTest): Tệp XML. \ res \ layout \ test.xml dòng # -1 (xin lỗi, chưa được triển khai): Lỗi thổi phồng lớp com.viewpagerindicator.CirclePageIndicator

Chỉnh sửa (tháng 12 năm 2014)

Xin lưu ý rằng dây buộc sau đây đã được David Rabinowitz thêm vào sau này. Mặc dù có liên quan, nhưng nó không phải là vấn đề tôi đang phải đối mặt vào thời điểm đó.


Đây là dấu vết ngăn xếp:

android.view.InflateException: XML file .\res\layout\activity_home.xml line #-1 (sorry, not yet implemented): Error inflating class com.test.custom.RobotoTextView
    at android.view.LayoutInflater.createView(LayoutInflater.java:613)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:687)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
    at org.robolectric.tester.android.view.RoboWindow.setContentView(RoboWindow.java:82)
    at org.robolectric.shadows.ShadowActivity.setContentView(ShadowActivity.java:273)
    at android.app.Activity.setContentView(Activity.java)
    at com.example.testrobocustomfont.MainActivity.onCreate(MainActivity.java:12)
    at com.example.testrobocustomfont.MainActivityTest.setUp(MainActivityTest.java:28)
    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.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:241)
    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.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:177)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
    at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_createView(LayoutInflater.java:587)
    at android.view.LayoutInflater.createView(LayoutInflater.java)
    at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_createViewFromTag(LayoutInflater.java:687)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java)
    at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_rInflate(LayoutInflater.java:746)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java)
    at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.java:489)
    at android.view.LayoutInflater.inflate(LayoutInflater.java)
    at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.java:396)
    at android.view.LayoutInflater.inflate(LayoutInflater.java)
    at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.java:352)
    at android.view.LayoutInflater.inflate(LayoutInflater.java)
    at org.robolectric.tester.android.view.RoboWindow.setContentView(RoboWindow.java:82)
    at org.robolectric.shadows.ShadowActivity.setContentView(ShadowActivity.java:273)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.robolectric.bytecode.ShadowWrangler$ShadowMethodPlan.run(ShadowWrangler.java:455)
    at android.app.Activity.setContentView(Activity.java)
    at com.example.testrobocustomfont.MainActivity.onCreate(MainActivity.java:12)
    at com.example.testrobocustomfont.MainActivityTest.setUp(MainActivityTest.java:28)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    ... 22 more
Caused by: java.lang.RuntimeException: error converting RobotoMedium.ttf using EnumConverter
    at org.robolectric.shadows.Converter.convertAndFill(Converter.java:150)
    at org.robolectric.shadows.Converter.convertAndFill(Converter.java:50)
    at org.robolectric.shadows.ShadowResources.createTypedArray(ShadowResources.java:228)
    at org.robolectric.shadows.ShadowResources.attrsToTypedArray(ShadowResources.java:203)
    at org.robolectric.shadows.ShadowResources.access$000(ShadowResources.java:51)
    at org.robolectric.shadows.ShadowResources$ShadowTheme.obtainStyledAttributes(ShadowResources.java:460)
    at android.content.res.Resources$Theme.obtainStyledAttributes(Resources.java)
    at android.widget.TextView.__constructor__(TextView.java:561)
    at android.widget.TextView.<init>(TextView.java:447)
    at android.widget.TextView.<init>(TextView.java:442)
    at com.test.custom.RobotoTextView.<init>(RobotoTextView.java:16)
    at android.view.LayoutInflater.createView(LayoutInflater.java:587)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:687)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
    at org.robolectric.tester.android.view.RoboWindow.setContentView(RoboWindow.java:82)
    at org.robolectric.shadows.ShadowActivity.setContentView(ShadowActivity.java:273)
    at android.app.Activity.setContentView(Activity.java)
    at com.example.testrobocustomfont.MainActivity.onCreate(MainActivity.java:12)
    at com.example.testrobocustomfont.MainActivityTest.setUp(MainActivityTest.java:28)
    ... 22 more
Caused by: java.lang.RuntimeException: no value found for RobotoMedium.ttf
    at org.robolectric.shadows.Converter$EnumOrFlagConverter.findValueFor(Converter.java:375)
    at org.robolectric.shadows.Converter$EnumConverter.fillTypedValue(Converter.java:343)
    at org.robolectric.shadows.Converter$EnumConverter.fillTypedValue(Converter.java:336)
    at org.robolectric.shadows.Converter.convertAndFill(Converter.java:148)
    at org.robolectric.shadows.Converter.convertAndFill(Converter.java:50)
    at org.robolectric.shadows.ShadowResources.createTypedArray(ShadowResources.java:228)
    at org.robolectric.shadows.ShadowResources.attrsToTypedArray(ShadowResources.java:203)
    at org.robolectric.shadows.ShadowResources.access$000(ShadowResources.java:51)
    at org.robolectric.shadows.ShadowResources$ShadowTheme.obtainStyledAttributes(ShadowResources.java:460)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.robolectric.bytecode.ShadowWrangler$ShadowMethodPlan.run(ShadowWrangler.java:455)
    at android.content.res.Resources$Theme.obtainStyledAttributes(Resources.java)
    at android.widget.TextView.$$robo$$TextView_347d___constructor__(TextView.java:561)
    at android.widget.TextView.<init>(TextView.java:447)
    at android.widget.TextView.<init>(TextView.java:442)
    at com.test.custom.RobotoTextView.<init>(RobotoTextView.java:16)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
    at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_createView(LayoutInflater.java:587)
    at android.view.LayoutInflater.createView(LayoutInflater.java)
    at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_createViewFromTag(LayoutInflater.java:687)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java)
    at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_rInflate(LayoutInflater.java:746)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java)
    at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.java:489)
    at android.view.LayoutInflater.inflate(LayoutInflater.java)
    at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.java:396)
    at android.view.LayoutInflater.inflate(LayoutInflater.java)
    at android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.java:352)
    at android.view.LayoutInflater.inflate(LayoutInflater.java)
    at org.robolectric.tester.android.view.RoboWindow.setContentView(RoboWindow.java:82)
    at org.robolectric.shadows.ShadowActivity.setContentView(ShadowActivity.java:273)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.robolectric.bytecode.ShadowWrangler$ShadowMethodPlan.run(ShadowWrangler.java:455)
    at android.app.Activity.setContentView(Activity.java)
    at com.example.testrobocustomfont.MainActivity.onCreate(MainActivity.java:12)
    at com.example.testrobocustomfont.MainActivityTest.setUp(MainActivityTest.java:28)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    ... 22 more

Xin các bạn chỉ cho tôi hướng đi đúng không? Tôi hết ý tưởng. Cảm ơn.


1
Bạn có thể đăng một dấu vết ngăn xếp đầy đủ?
Corey D

Bạn đang sử dụng phông chữ tùy chỉnh hay chế độ xem tùy chỉnh sử dụng phông chữ tùy chỉnh? Tôi nghĩ @joecks đang đi đúng hướng với câu trả lời của họ. Android không thể hiển thị phông chữ tùy chỉnh trong bản xem trước (tức là khi bạn đang xem xml trong Eclipse) và vấn đề tương tự có thể xảy ra ở đây. Nếu bạn kiểm soát chế độ xem văn bản, hãy thử bao bọc mã truy xuất kiểu bằngif (!isInEditMode())
karl

Bạn có thể thấy chế độ xem tùy chỉnh trong bản xem trước đồ họa xml bố cục không?
JstnPwll


1
OP có thể đăng dấu vết ngăn xếp của anh ấy / cô ấy để chúng tôi có thể giúp đỡ không? Có dấu vết ngăn xếp của người khác không phải là rất hữu ích. Cảm ơn.
Caleb

Câu trả lời:


4

Tôi kiểm tra các lượt xem trong cùng một lớp thử nghiệm với Hoạt động sử dụng chúng. Trong trường hợp này, tôi yêu cầu Robolectric đưa ra một ví dụ của Hoạt động đó và từ đó tôi nhận được một phiên bản của chế độ xem tăng cao:

@Before
public void setup(){
    activity = Robolectric.buildActivity(MyActivity.class).create().get();
    View view = LayoutInflater.from(activity).inflate(R.layout.myView, null);
}
@Test
 public void allElementsInViewProduct(){
     assertNotNull(view.findViewById(R.id.view1));
     assertNotNull(view.findViewById(R.id.view2));
     assertNotNull(view.findViewById(R.id.view3));
 }

LE: Tôi sử dụng Robolectric 3.0 nên tôi không chắc liệu điều này có áp dụng cho bạn hay không.


3

Vấn đề:

Sự cố này xảy ra, bởi vì gradle hợp nhất các phụ thuộc dự án (ví dụ compile project(':lib-custom'):) và phụ thuộc bên ngoài (ví dụ compile 'lib.package:name:1.1.0':) theo cách khác nhau. Sau khi các phụ thuộc được hợp nhất, ứng dụng có R.javatệp với tất cả các trường tài nguyên (màu, id, có thể vẽ, ...). Nhưng R.javatệp được tạo trông sẽ khác sau khi hợp nhất các mô-đun con và các phụ thuộc bên ngoài.

Vấn đề này chỉ tồn tại với các dự án có chế độ xem tùy chỉnh trong mô-đun con . Trong trường hợp phụ thuộc bên ngoài, có một vấn đề khác, có thể dễ dàng khắc phục. Đọc về các loại phụ thuộc tại đây .

Đối với R.javatệp kết quả phụ thuộc dự án chứa tất cả các số nhận dạng tài nguyên, nhưng các số nhận dạng từ mô-đun con không bằng với các số nhận dạng số nguyên ban đầu của chúng:

com.lib.custom.R.color.primary != com.main.project.R.color.primary

Đối với R.javatệp đã hợp nhất phụ thuộc bên ngoài chỉ là kết quả hợp nhất của các tệp R.java từ tất cả các tệp phụ thuộc bên ngoài

com.lib.custom.R.color.primary == com.main.project.R.color.primary

Giải pháp:

Tôi đã tìm thấy hai giải pháp khả thi:

  1. Chuyển đổi các phần phụ thuộc của bạn từ submodule sang bên ngoài nếu có thể. Ví dụ đối với chỉ báo viepager có một mục trong kho lưu trữ maven.org - fr.avianey.com.viewpagerindicator: library. Nhưng điều này vẫn chưa đủ - bạn cần thêm mục liên quan vào tệp project.properties vào sourceSet chính của bạn. Thông tin thêm tại đây

Thí dụ:

// add this dependency to your gradle file instead of project dependency
compile 'fr.avianey.com.viewpagerindicator:library:2.4.1@aar'

// add library dependencies for robolectric (now robolectric knows 
// about additional libraries to load resources)
android.library.reference.1=../../../app/build/intermediates/exploded-aar/fr.avianey.com.viewpagerindicator/library/2.4.1

Bạn có thể kiểm tra khác biệt cho giải pháp này tại đây

  1. Di chuyển tất cả các chế độ xem tùy chỉnh của bạn trong ứng dụng chính của bạn. Việc chuyển Chế độ xem tùy chỉnh sang ứng dụng không phải là cách tốt chỉ vì thử nghiệm đơn vị, nhưng điều này cũng sẽ khắc phục sự cố với Error inflating class.

Tôi thích giải pháp đầu tiên hơn nhưng đôi khi không thể thay đổi sự phụ thuộc của dự án thành bên ngoài.

Tôi cũng sẽ báo cáo về vấn đề này cho nhóm Robolectric.

PS Tôi có dự án trên github liên quan đến vấn đề này.


0

mTestRoboActivityView = LayoutInflater.from(new Activity()).inflate(R.layout.test, null);

Trong dòng mã này, bạn đã sử dụng 'Hoạt động mới ()' có nghĩa là phiên bản của Hoạt động mới, không dành cho Hoạt động hiện tại của bạn. Bạn có thể giải quyết vấn đề này bằng cách chuyển phiên bản trên Activity hiện tại. Sử dụng như thế này-

public class TestRoboActivityTest {
private View mTestRoboActivityView;
private Context mContext;

public TestRoboActivityTest(Context mContext){
    this.mContext=mContext;
}

@Before
public void setUp() throws Exception {
    mTestRoboActivityView = (LayoutInflater.from(mContext)).inflate(R.layout.test, null);
}

@After
public void tearDown() throws Exception {
    mTestRoboActivityView = null;
}

@Test
public void testSanity() throws Exception {
    Assert.assertNotNull(mTestRoboActivityView);
}}

Tôi không chắc rằng mã trên hoạt động tốt nhưng sử dụng để tham khảo, ví dụ của Hoạt động hiện tại. Tham khảo nó có thể giúp bạn.


0

Bạn không thể tăng lượt xem trong Robo điện vì nó không sử dụng khung hoàn chỉnh của Android mà thay vào đó, chế nhạo tất cả các API của Android.

Bạn không nên sử dụng rô-bốt để kiểm tra hành vi hiển thị chế độ xem thực tế. Nó được sử dụng cho các bài kiểm tra đơn vị và chỉ để kiểm tra logic kinh doanh của bạn chứ không phải xem bản vẽ / hiển thị, v.v. Để đạt được điều đó, Bạn có thể lập trình tạo các đối tượng xem và mô phỏng các bộ phận nhất định cần hệ thống android (Sử dụng thứ gì đó như Mockito hoặc Powermock ) . ví dụ: kiểm tra chế độ xem đơn giản trong robot:

MyCustomView view = new MyCustomView();
assertNotNull(view.setSomeNo(2);
assertTrue(2, view.getSomeNo());

Ngoài ra, nếu bạn muốn kiểm tra kết xuất xem của bạn trông như thế nào hoặc hiển thị, v.v., bạn nên sử dụng các khung kiểm tra chức năng như Espresso hoặc Robotium chạy trên thiết bị thực tế.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.