Làm cách nào để chạy thử nghiệm Gradle khi tất cả các thử nghiệm đều TĂNG LÊN?


130

Tôi đã thiết lập kịch bản lớp của tôi. Khi tôi thực hiện bản dựng Gradle, mọi thứ đều hoạt động và nó chạy các bài kiểm tra jUnit.

Sau đó khi tôi chạy thử nghiệm Gradle, tôi nhận được như sau:

C:\Users\..\..\Project>gradle test
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE

Khi tôi thực hiện gradle clean, thì Gradle build hoạt động, tất nhiên ... Tôi muốn chỉ có thể thiết lập lại các bài kiểm tra, không xây dựng toàn bộ dự án: tôi nên làm điều này như thế nào?


3
Điều này có vẻ không cần thiết, dựa trên thông tin đã cho. Nếu cả mã ứng dụng và mã kiểm tra đều không thay đổi, tại sao bạn cần chạy lại các bài kiểm tra?
Jolta

10
@Jolta Một số thử nghiệm trong mã của tôi có liên quan đến đầu vào 3 bên, tôi đang chạy thử nghiệm không chỉ để đảm bảo rằng tôi không đặt bất kỳ lỗi nào vào mã, mà còn để kiểm tra xem có gì thay đổi trên đầu vào 3 bên không mà tôi đang nhận được
USer22999299

4
Xin lỗi vì quá kén chọn, nhưng tôi thực sự không nghĩ rằng đây là cách suy nghĩ chính xác về vấn đề này: nếu bạn có đầu vào 3 bên thay đổi không phải là cách xử lý chính xác để chế nhạo những đầu vào này theo một cách nào đó? Kiểm tra thực sự nên là về kiểm tra mã bạn đang viết. Bạn có gặp nguy hiểm khá rõ ràng khi nhận được thông báo sai nếu bạn dựa vào đầu vào của 3 bên là không thể chấp nhận? Không phải chiến lược là để phục vụ cho vấn đề đầu vào như là một phần của mã ứng dụng của bạn?
mike gặm nhấm

9
@mikerodent xem xét việc kiểm tra mã của bạn đối với dịch vụ trực tuyến của bên thứ 3. Bạn sẽ muốn theo dõi các thay đổi có thể có trong API dịch vụ để có thể đáp ứng với các bản sửa lỗi được triển khai càng sớm càng tốt. Không phải CI kiểm tra một cách tốt để làm điều đó sao? Sử dụng một giả sẽ chỉ cho bạn biết mã của riêng bạn không có hồi quy, nhưng các phụ thuộc vẫn có thể có thay đổi. sử dụng dịch vụ thực tế sẽ chỉ ra rằng sản phẩm của bạn thực sự có thể thực hiện các hoạt động dự kiến ​​trong môi trường hiện tại.
Elist

5
Điều này cũng hợp lệ theo quan điểm kiểm thử tích hợp trong đó quan điểm của kiểm thử là xác thực việc tích hợp mã của bạn với các bit mã khác, trong đó không phù hợp để giả định trong các phụ thuộc
1800 THÔNG TIN

Câu trả lời:


171

Một tùy chọn sẽ là sử dụng --rerun-taskscờ trong dòng lệnh . Điều này sẽ chạy lại tất cả các nhiệm vụ thử nghiệm và tất cả các nhiệm vụ mà nó phụ thuộc vào.

Nếu bạn chỉ quan tâm đến việc chạy lại các bài kiểm tra thì một lựa chọn khác sẽ là làm sạch lớp kết quả các bài kiểm tra trước khi thực hiện các bài kiểm tra. Điều này có thể được thực hiện bằng cách sử dụng các cleanTestnhiệm vụ.

Một số nền tảng - plugin Java định nghĩa một tác vụ sạch cho từng tác vụ khác. Theo tài liệu :

CleanTaskName - Xóa các tệp được tạo bởi tác vụ được chỉ định. CleanJar sẽ xóa tệp JAR được tạo bởi tác vụ jar và CleanTest sẽ xóa kết quả kiểm tra được tạo bởi tác vụ kiểm tra.

Do đó, tất cả những gì bạn cần để chạy lại bài kiểm tra của mình là cũng chạy cleanTesttác vụ, tức là:
gradle cleanTest test


3
gradle cleanTest testkhông chạy lại các bài kiểm tra, nó làm sạch đầu ra của chúng, nhưng testtác vụ vẫn sẽ nhận được kết quả kiểm tra từ bộ đệm - xem github.com/gradle/gradle/issues/9153
dan.m là người dùng 2331368

3
Nhận xét trên là đúng. Nhưng nếu bạn sử dụng --no-build-cache, thì nó sẽ hoạt động như mong đợi, vd gradle cleanTest test --no-build-cache.
vRallev

51

Tùy chọn khác sẽ là thêm sau đây trong build.gradle của bạn:

test.outputs.upToDateWhen {false}

1
Tôi đã sử dụng kỹ thuật này cho một funcTestnhiệm vụ tôi tạo ra để chạy các bài kiểm tra chức năng.
pharsicle

4
Đây là một cách tiếp cận tốt hơn nhiều so với câu trả lời được chấp nhận, vì nó sẽ chỉ được áp dụng cho nhiệm vụ mong muốn. Có upToDateWhenthể được sử dụng theo bất kỳ cách "điều khiển mã" nào như thuộc tính hệ thống, biến môi trường, thuộc tính dự án, v.v.
mkobit

1
Như câu trả lời stackoverflow.com/a/52484259 4320175 đề cập đến, có một bài đăng blog hữu ích blog.gradle.org/stop-rerasty-tests giải thích tại sao phương pháp này không được đề xuất như một cách tiếp cận chung. Tuy nhiên, tôi đồng ý rằng nó có thể hữu ích và không đạt được những gì câu hỏi yêu cầu.
JulianHarty

Vâng, đây là câu trả lời ngày, khi tôi viết Gradle này ở phiên bản 2.11 và mới bắt đầu có thể sử dụng được, nhưng vẫn có nhiều cạnh thô, được đánh bóng ngày nay.
František Hartman

1
Câu trả lời chính xác!!! Đã vượt qua nó bằng một tham số : gradle test -Prerun-tests. Mã trong build.gradle:if(project.hasProperty("rerun-tests")) { test.outputs.upToDateWhen {false} }
AlikElzin-kilaka


17

Đây gần đây là chủ đề trên bài đăng trên blog của Gradle Dừng chạy lại bài kiểm tra của bạn . Các tác giả cho thấy một ví dụ sử dụng outputs.upToDateWhen { false }và giải thích lý do tại sao nó là sai:

Điều này không thực sự buộc chạy lại

Điều mà tác giả của đoạn trích này có lẽ muốn nói là Luôn luôn chạy lại các bài kiểm tra của tôi. Đó không phải là những gì đoạn trích này làm. Nó sẽ chỉ đánh dấu nhiệm vụ lỗi thời, buộc Gradle phải tạo lại đầu ra. Nhưng đây là điều, nếu bộ đệm xây dựng được bật, Gradle không cần chạy tác vụ để tạo lại đầu ra. Nó sẽ tìm thấy một mục trong bộ đệm và giải nén kết quả vào thư mục đầu ra của bài kiểm tra.

Điều này cũng đúng với đoạn trích này:

test.dependsOn cleanTest

Gradle sẽ giải nén các kết quả kiểm tra từ bộ đệm xây dựng sau khi đầu ra đã được làm sạch, vì vậy sẽ không có gì được chạy lại. Nói tóm lại, những đoạn trích này đang tạo ra một no-op rất đắt tiền.

Nếu bây giờ bạn đang nghĩ về Được rồi, tôi sẽ tắt bộ nhớ cache quá, hãy để tôi nói cho bạn biết tại sao bạn không nên.

Sau đó, tác giả tiếp tục giải thích tại sao chạy lại một số bài kiểm tra là lãng phí thời gian:

Phần lớn các bài kiểm tra của bạn nên có tính xác định, tức là được cung cấp cùng một đầu vào mà chúng sẽ tạo ra cùng một kết quả.

Trong một số trường hợp bạn muốn chạy lại các bài kiểm tra mà mã không thay đổi, bạn nên mô hình hóa chúng làm đầu vào. Dưới đây là cả hai ví dụ từ bài đăng trên blog cho thấy việc thêm một đầu vào để tác vụ sẽ sử dụng nó trong quá trình kiểm tra cập nhật của nó.

task randomizedTest(type: Test) {
  systemProperty "random.testing.seed", new Random().nextInt()
}

task systemIntegrationTest(type: Test) {
  inputs.property "integration.date", LocalDate.now()
}

Tôi khuyên bạn nên đọc toàn bộ bài viết trên blog.


8
Điều này nghe có vẻ tuyệt vời cho trường hợp sử dụng cụ thể mà bạn đang nói đến, nhưng tôi đang viết các bài kiểm tra sau triển khai đối với một dịch vụ web bên ngoài trực tiếp và tình cờ sử dụng Junit và gradle để thực hiện điều này. Các mã được kiểm tra không sống trong repo, và trong thực tế có không có 'mã ứng dụng' bởi vì tôi thực sự thử nghiệm một hệ thống sản xuất trực tiếp chứ không phải là mã riêng của mình. Cảm ơn câu trả lời, điều này rất hữu ích! Chỉ muốn chỉ ra rằng có những trường hợp sử dụng bổ sung yêu cầu chạy lại các bài kiểm tra mỗi lần ngay cả khi không có loại mã nào biết về việc thay đổi
Brandon

11

Đây là một giải pháp sử dụng tệp "build.gradle", trong trường hợp bạn không muốn sửa đổi dòng lệnh của mình:

test {
    dependsOn 'cleanTest'
    //Your previous task details (if any)
}

Và đây là đầu ra. Lưu ý 2 thay đổi từ đầu ra trước đó của bạn:

1) Một tác vụ 'CleanTest' mới xuất hiện trong đầu ra.

2) 'kiểm tra' luôn được làm sạch (nghĩa là không bao giờ 'LÊN TỚI NGÀY') để nó được thực hiện mỗi lần:

$ gradle build
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:findMainClass
:jar
:bootRepackage
:assemble
:cleanTest
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test
:check
:build

1
chạy cleanTesttrước testsẽ không chạy lại các bài kiểm tra, nó sẽ xóa đầu ra của chúng, nhưng tác vụ kiểm tra vẫn sẽ nhận được kết quả kiểm tra từ bộ đệm - xem github.com/gradle/gradle/issues/9153
dan.m là người dùng 2331368

8

--rerun-tasks hoạt động, nhưng không hiệu quả vì nó chạy lại tất cả các nhiệm vụ.

cleanTest tự nó có thể không đủ do xây dựng bộ đệm.

vì vậy, cách tốt nhất để thực hiện điều này là:

./gradlew --no-build-cache cleanTest test

0

Ngoài ra, phải thêm --rerun-taskslà thực sự dư thừa. Không bao giờ xảy ra. Tạo một --no-rerun-tasksvà làm cho --rerun-tasksmặc định khicleanTask



-4

Tôi nghĩ rằng đây là một câu hỏi hợp lệ được đưa ra rằng Gradle có thể chạy lệnh này testvà điều không xảy ra là không có gì xảy ra!

Nhưng tôi sẽ đặt câu hỏi về sự cần thiết phải làm điều này, như Jolta đã nói trong bình luận của mình: nếu không có mã nào thay đổi tại sao bạn cần phải kiểm tra lại? Nếu bạn nghi ngờ về đầu vào của bên thứ ba, tôi muốn nói rằng bạn cần phục vụ cho điều này trong mã ứng dụng của mình. Nếu bạn lo lắng rằng mã của bạn có thể "không ổn định", nghĩa là có thể vượt qua tất cả các bài kiểm tra lần đầu tiên nhưng không phải lần thứ hai (hoặc lần thứ 100), bạn không cần phải suy nghĩ về lý do tại sao bạn có những nghi ngờ này và giải quyết chúng?

Cá nhân tôi nghĩ rằng đây là một lỗi thiết kế (rất nhỏ) trong Gradle: nếu mọi thứ hoàn toàn cập nhật, thay vì đi "BUILD SUCCESSFUL" thì nên nói "KHÔNG THAY ĐỔI CUỐI CÙNG THÀNH CÔNG CUỐI CÙNG: KHÔNG LÀM ĐƯỢC".


3
"Bạn không cần phải suy nghĩ về lý do tại sao bạn có những nghi ngờ này và giải quyết chúng?": Vâng, nhưng để có được dữ liệu để suy nghĩ, tôi muốn chạy thử nghiệm một vài lần và xem điều gì sẽ xảy ra. Điều đó thật điên rồ?
mhsmith

1
@mikerodent Tôi đồng ý một phần với quan điểm của bạn. Có những trường hợp "dễ dàng", điển hình là các thử nghiệm đơn vị whitebox đơn giản, trong đó không có thay đổi mã có nghĩa là không có gì thực sự để kiểm tra lại. Hãy suy nghĩ về các bài kiểm tra với sự phụ thuộc mặc dù. "Ồ vâng, docker không chạy, v.v." Có những thử nghiệm trong đó cơ sở hạ tầng (và trong nhà phát triển), người thiết lập các phụ thuộc (chúng được "cung cấp") chứ không phải là bản dựng. Trong những trường hợp này, tôi luôn muốn có thể chạy lại.
dbalakirev

@dbalakirev Vâng, điều này xảy ra với tôi ... nhưng bạn không nên chế giễu vai trò của những phụ thuộc này, chẳng hạn như Docker ...? Ý tôi là, nếu bạn không làm điều đó, bạn sẽ không lưu trữ những vấn đề trong tương lai chứ? Tôi không nói tôi chắc chắn 100%, nhưng điều tôi nghĩ là tôi đang nói rằng các bài kiểm tra của bạn, trong một thế giới chắc chắn lý tưởng hơn chúng ta, bao gồm tất cả các cơ sở.
mike gặm nhấm

Bạn có thể chế giễu có, trong đó bạn có một phụ thuộc (docker) mà nếu thất bại với bạn, điều đó có nghĩa là bạn muốn chạy lại ngay cả khi mã không thay đổi. Tôi muốn nhấn mạnh suy nghĩ này là không cho unit tests hoặc kiểm tra nơi 1. bạn cố gắng để tránh phụ thuộc 2. hoặc ít nhất là mô hình chúng bằng cách sử dụng khuôn khổ kiểm tra, nhưng khi họ đang thực sự "cung cấp" nếu bạn sẽ.
dbalakirev

2
__ nếu không có mã nào thay đổi tại sao bạn cần kiểm tra lại? __ Bạn đã nghe về các bài kiểm tra tích hợp chưa?
Bogdan Mart
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.