Kiểm tra đơn vị Android Studio: đọc dữ liệu (đầu vào) tệp


96

Trong bài kiểm tra đơn vị, làm cách nào tôi có thể đọc dữ liệu từ tệp json trên hệ thống tệp (máy tính để bàn) của mình mà không cần mã hóa đường dẫn?

Tôi muốn đọc đầu vào thử nghiệm (cho các phương pháp phân tích cú pháp của tôi) từ một tệp thay vì tạo Chuỗi tĩnh.

Tệp ở cùng vị trí với mã kiểm thử đơn vị của tôi, nhưng tôi cũng có thể đặt nó ở một nơi khác trong dự án nếu cần. Tôi đang sử dụng Android Studio.


3
Tôi đã thử hầu hết mọi kết hợp với IOUtils.toString (this.getClass (). GetResourceAsStream ("test_documents.json"), "UTF-8"), nó luôn trả về null. Có lẽ vì các tệp sẽ không được đưa vào jar.
Frank

Chúng ta đang nói về các bài kiểm tra đơn vị liên quan đến trình giả lập / thiết bị Android?
AndroidEx

@ Android777 Tôi nghĩ rằng chúng ta đang nói về hỗ trợ kiểm tra đơn vị mới được giới thiệu trong phiên bản gần đây của Android Studio tools.android.com/tech-docs/unit-testing-support
akhy

@Frank bạn đặt ở test_documents.jsonđâu? thư mục tài sản?
akhy

Có, chúng tôi đang nói về hỗ trợ kiểm tra đơn vị mới, không liên quan đến trình giả lập / thiết bị. Tôi đã không đặt nó trong tài sản dir, vì sau đó nó được đóng gói với apk trực tiếp. Tôi đã đặt nó trong cùng một thư mục với các tệp thử nghiệm (java).
Frank

Câu trả lời:


149

Tùy thuộc vào android-gradle-pluginphiên bản:

1. phiên bản 1.5 trở lên:

Chỉ cần đặt tệp json vào src/test/resources/test.jsonvà tham chiếu nó dưới dạng

classLoader.getResource("test.json"). 

Không cần sửa đổi gradle.

2. phiên bản dưới 1.5 : (hoặc nếu vì lý do nào đó mà giải pháp trên không hoạt động)

  1. Đảm bảo rằng bạn đang sử dụng ít nhất phiên bản Plugin Android Gradle 1.1 . Nhấp vào liên kết để thiết lập Android Studio đúng cách.

  2. Tạo testthư mục. Đặt các lớp kiểm tra đơn vị trong javathư mục và đặt tệp tài nguyên của bạn trong resthư mục. Android Studio nên đánh dấu chúng như sau:

    nhập mô tả hình ảnh ở đây

  3. Tạo gradletác vụ để sao chép tài nguyên vào thư mục lớp để hiển thị chúng cho classloader:

    android{
       ...
    }
    
    task copyResDirectoryToClasses(type: Copy){
        from "${projectDir}/src/test/res"
        into "${buildDir}/intermediates/classes/test/debug/res"
    }
    
    assembleDebug.dependsOn(copyResDirectoryToClasses)
    
  4. Bây giờ bạn có thể sử dụng phương pháp này để lấy Filetham chiếu cho tài nguyên tệp:

    private static File getFileFromPath(Object obj, String fileName) {
        ClassLoader classLoader = obj.getClass().getClassLoader();
        URL resource = classLoader.getResource(fileName);
        return new File(resource.getPath());
    }
    
    @Test
    public void fileObjectShouldNotBeNull() throws Exception {
        File file = getFileFromPath(this, "res/test.json");
        assertThat(file, notNullValue());
    }
    
  5. Chạy bài kiểm tra đơn vị bằng Ctrl+ Shift+ F10trên cả lớp hoặc phương pháp kiểm tra cụ thể.

1
Tuyệt vời! Bản chỉnh sửa của bạn, không có thử nghiệm nhạc cụ, hoạt động như một sự quyến rũ, cảm ơn!
Frank

4
Đó là một giải pháp hay, nhưng không phải lúc nào nó cũng hoạt động. Nếu bạn thực hiện chạy tác vụ sạch và sau đó chạy testDebug thì nó không thành công. Về cơ bản, nhà phát triển cần biết rằng anh ta phải chạy tác vụ assemblyDebug trước khi testDebug. Bạn có bất kỳ đề nghị nào để cải thiện điều này?
joaoprudencio

18
Với AndroidStudio 1.5 với plugin android 1.5.0, hãy đặt tệp json của bạn ở đây src/test/resources/test.jsonvà tham chiếu nó dưới dạng classLoader.getResource("test.json"). Không cần sửa đổi gradle. Các thư mục lồng nhau bên trong resourcescũng đang hoạt động.
Sergii Pechenizkyi

6
Câu trả lời không đầy đủ. Là classLoadergì? đặt dòng mã này ở đâu? bạn có thể làm gì với kết quả trả về ?. Vui lòng cung cấp mã hoàn chỉnh hơn. -1
voghDev

3
Để đọc ./src/test/resources/file.txttrong Kotlin:TestClassName::class.java.getResource("/file.txt")!!.readText()
Erik

76

Đối với các bài kiểm tra đơn vị cục bộ (so với bài kiểm tra thiết bị), bạn có thể đặt các tệp bên dưới src/test/resourcesvà đọc chúng bằng cách sử dụng classLoader. Ví dụ: mã sau sẽ mở myFile.txttệp trong thư mục tài nguyên.

InputStream in = this.getClass().getClassLoader().getResourceAsStream("myFile.txt");

Nó hoạt động với

  • Android Studio 1.5.1
  • plugin gradle 1.3.1

Điều này không hiệu quả với tôi, vui lòng xem câu hỏi của tôi tại đây stackoverflow.com/questions/36295824/…
Tyler Pfaff,

5
Điều này đã làm việc cho tôi, khi tôi thay đổi từ "src / test / res" thành "src / test / resources". Sử dụng Android Studio 2.0 RC 3, gradle: 2.0.0-rc3
Alex Bravo

đã hoạt động như mong đợi. Nhưng quá trình kiểm tra vẫn vượt qua ngay cả khi tệp không có sẵn trong "src / test / resources /", ví dụ: "rules.xml", nhưng kết quả InputStream là rỗng trong trường hợp này.
anand krish

4
kotlin:val myFile = ClassLoader.getSystemResource("myFile.txt").readText()
jj.

Làm việc như một sự quyến rũ!
Amit Bhandari

15

Trong trường hợp của tôi, giải pháp là thêm vào tệp gradle

sourceSets {
    test.resources.srcDirs += 'src/unitTests/resources'
  } 

Sau khi nó, mọi thứ đã được tìm thấy bởi AS 2.3.1

javaClass.classLoader.getResourceAsStream("countries.txt")

Tôi đã làm một cái gì đó rất giống (Kotlin): 1. tạo thư mục và tệp tại: root/app/src/test/resources/test.json 2. đọc dữ liệu như thế này:val jsonFile = ClassLoader.getSystemResource("test.json").readText()
jj.

8

Tôi đã gặp rất nhiều vấn đề với tài nguyên thử nghiệm trong Android Studio nên tôi đã thiết lập một vài thử nghiệm để rõ ràng. Trong mobiledự án (Ứng dụng Android) của tôi, tôi đã thêm các tệp sau:

mobile/src/test/java/test/ResourceTest.java
mobile/src/test/resources/test.txt
mobile/src/test/resources/test/samePackage.txt

Lớp kiểm tra (tất cả các bài kiểm tra đều vượt qua):

assertTrue(getClass().getResource("test.txt") == null);
assertTrue(getClass().getResource("/test.txt").getPath().endsWith("test.txt"));
assertTrue(getClass().getResource("samePackage.txt").getPath().endsWith("test/samePackage.txt"));
assertTrue(getClass().getResource("/test/samePackage.txt").getPath().endsWith("test/samePackage.txt"));
assertTrue(getClass().getClassLoader().getResource("test.txt").getPath().endsWith("test.txt"));
assertTrue(getClass().getClassLoader().getResource("test/samePackage.txt").getPath().endsWith("test/samePackage.txt"));

Trong cùng một dự án gốc, tôi có một dự án Java (không phải Android) được gọi data. Nếu tôi thêm các tệp giống nhau vào dự án dữ liệu:

data/src/test/java/test/ResourceTest.java
data/src/test/resources/test.txt
data/src/test/resources/test/samePackage.txt

Sau đó, tất cả các thử nghiệm ở trên sẽ thất bại nếu tôi thực hiện chúng từ Android Studio, nhưng chúng chuyển qua dòng lệnh với ./gradlew data:test. Để giải quyết vấn đề đó, tôi sử dụng bản hack này (ở Groovy)

def resource(String path) {
    getClass().getResource(path) ?:
            // Hack to load test resources when executing tests from Android Studio
            new File(getClass().getClassLoader().getResource('.').path
                    .replace('/build/classes/test/', "/build/resources/test$path"))
}

Sử dụng: resource('/test.txt')

Android Studio 2.3, Gradle 3.3


Câu trả lời tuyệt vời (sau 45 phút tìm kiếm 😌). Nó tập trung vào trọng tâm của một số vấn đề và giúp dễ dàng sao chép kết quả bằng chính các bài kiểm tra. Fwiw, Trong AS 2.3.1, Gradle 2.3.1, các getClassLoader()phiên bản hoạt động như mong đợi. Tức là họ tìm thấy các tệp, cả hai đều chạy từ Android Studio VÀ từ dòng lệnh trên máy macOS của tôi và trên máy chủ Linux CI (CircleCI). Vì vậy, tôi đi với điều đó và hy vọng Gradle 3.3 không phá vỡ nó sau này ...
mm2001

Đẹp! Tôi đang gặp sự cố tải tài nguyên tương tự ở đây. AS 2.3.2, Gradle 3.3. Các bài kiểm tra hoạt động từ dòng lệnh nhưng không thông qua AS, do build/resources/testkhông được bao gồm trong classpath tương tác.
Mark McKenna

6

Nếu bạn đi tới Chạy -> Chỉnh sửa cấu hình -> JUnit và sau đó chọn cấu hình chạy cho các bài kiểm tra đơn vị của bạn, sẽ có cài đặt 'Thư mục làm việc'. Điều đó sẽ trỏ đến bất kỳ tệp json của bạn ở đâu. Hãy nhớ rằng điều này có thể phá vỡ các bài kiểm tra khác.


và hơn là sử dụng this.getClass (). getResourceAsStream (test.json)? Tôi đã thêm các tệp ở đó, trong thư mục gốc của dự án, nó vẫn không tìm thấy tệp.
Frank

Điều này có thể được sử dụng để tải tệp bằng cách sử dụng new File()hoặc tương tự, nhưng nó không hoạt động trực tiếp với phương pháp tải classpath được mô tả ở trên. Nó cũng hơi phức tạp vì mỗi cấu hình chạy mới cần phải đặt dir hoạt động và theo mặc định dòng lệnh AS và Gradle thích sử dụng các dir làm việc khác nhau ... thật khó khăn
Mark McKenna

4

Tôi mặc dù tôi nên thêm những phát hiện của mình ở đây. Tôi biết điều này hơi cũ nhưng đối với các phiên bản mới hơn của Gradle, nơi KHÔNG có thư mục src / test / resources, mà chỉ có một thư mục tài nguyên duy nhất cho toàn bộ dự án, bạn phải thêm dòng này vào tệp Gradle của mình.

android {
   testOptions {
      unitTests {
         includeAndroidResources = true
      }
    }
}

Bằng cách này, bạn có thể truy cập tài nguyên của mình bằng:

 this.getClass().getClassLoader().getResourceAsStream(fileName);

Tôi đã tìm kiếm điều này và không thể tìm thấy câu trả lời, vì vậy tôi quyết định giúp những người khác ở đây.


1

Trên thực tế, đây là những gì đã làm việc cho tôi với Kiểm tra thiết bị (Chạy Android Studio phiên bản 3.5.3 , Plugin Android Gradle phiên bản 3.5.3 , phiên bản Gradle 6.0.1 ):

  1. Đặt các tệp của bạn vào src/androidTest/assetsthư mục
  2. Trong tệp thử nghiệm của bạn:

InputStream is = InstrumentationRegistry.getInstrumentation().getContext().getAssets().open("filename.txt");

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.