2009-09-20 20 views
11

Tôi có một lớp thử nghiệm, được viết bằng cú pháp JUnit4, có thể chạy trong nhật thực với tùy chọn "chạy dưới dạng kiểm tra junit" mà không bị lỗi. Khi tôi chạy cùng một thử nghiệm thông qua một mục tiêu ant tôi nhận được lỗi này:Các lớp kiểm tra JUnit4 có yêu cầu một hàm xây dựng không công khai không?

java.lang.Exception: Test class should have public zero-argument constructor 
at org.junit.internal.runners.MethodValidator.validateNoArgConstructor(MethodValidator.java:54) 
at org.junit.internal.runners.MethodValidator.validateAllMethods(MethodValidator.java:39) 
at org.junit.internal.runners.TestClassRunner.validate(TestClassRunner.java:33) 
at org.junit.internal.runners.TestClassRunner.<init>(TestClassRunner.java:27) 
at org.junit.internal.runners.TestClassRunner.<init>(TestClassRunner.java:20) 
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) 
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) 
at java.lang.reflect.Constructor.newInstance(Constructor.java:513) 
at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:26) 
at junit.framework.JUnit4TestAdapter.<init>(JUnit4TestAdapter.java:24) 
at junit.framework.JUnit4TestAdapter.<init>(JUnit4TestAdapter.java:17) 
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) 
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) 
at java.lang.reflect.Constructor.newInstance(Constructor.java:513) 
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.run(JUnitTestRunner.java:386) 
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.launch(JUnitTestRunner.java:911) 
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(JUnitTestRunner.java:768) 
Caused by: java.lang.NoSuchMethodException: dk.gensam.gaia.business.bonusregulering.TestBonusregulerAftale$Test1Reader.<init>() 
at java.lang.Class.getConstructor0(Class.java:2706) 
at java.lang.Class.getConstructor(Class.java:1657) 
at org.junit.internal.runners.MethodValidator.validateNoArgConstructor(MethodValidator.java:52) 

Tôi không có công khai không có nhà xây dựng arg trong lớp, nhưng điều này thực sự cần thiết?

Đây là mục tiêu kiến ​​của tôi

<target name="junit" description="Execute unit tests" depends="compile, jar-test"> 
     <delete dir="tmp/rawtestoutput"/> 
     <delete dir="test-reports"/> 
     <mkdir dir="tmp/rawtestoutput"/> 
     <junit printsummary="true" failureproperty="junit.failure" fork="true"> 
      <classpath refid="class.path.test"/> 
      <classpath refid="class.path.model"/> 
      <classpath refid="class.path.gui"/> 
      <classpath refid="class.path.jfreereport"/> 
      <classpath path="tmp/${test.jar}"></classpath> 
      <batchtest todir="tmp/rawtestoutput"> 
      <fileset dir="${build}/test"> 
       <include name="**/*Test.class" /> 
       <include name="**/Test*.class" /> 
      </fileset> 
      </batchtest> 
     </junit> 
     <junitreport todir="tmp"> 
      <fileset dir="tmp/rawtestoutput"/> 
      <report todir="test-reports"/> 
     </junitreport> 
     <fail if="junit. 
failure" message="Unit test(s) failed. See reports!"/> 
    </target> 

Lớp kiểm tra không có nhà xây dựng, nhưng nó có một lớp bên trong với modifier mặc định. Nó cũng có một lớp ẩn danh bên trong. Cả hai lớp bên trong cung cấp cho "Lớp kiểm tra phải có lỗi hàm tạo đối số 0 công khai". Tôi đang sử dụng phiên bản Ant 1.7.1 và JUnit 4.7

Trả lời

3

Cảm ơn tất cả vì đã dành thời gian và câu trả lời của bạn. Tôi hiện đã tìm được giải pháp. Trước đây tôi nghĩ đầu vào cho phần batchtest của đối tượng ant của tôi phải là các tệp .class nhưng cũng có thể sử dụng các tệp .java.

Điều đó giải quyết được vấn đề. Bây giờ nó không còn phàn nàn về các lớp bên trong thiếu các nhà xây dựng công cộng nữa.

<target name="junit" description="Execute unit tests"> 
<delete dir="tmp/rawtestoutput"/> 
<delete dir="test-reports"/> 
    <mkdir dir="tmp/rawtestoutput"/>  
    <junit printsummary="on" failureproperty="junit.failure" fork="true"> 
     <jvmarg value="-Duser=TBA -Dpassword=ibber11"/> 
     <classpath refid="class.path.test"/> 
     <classpath refid="class.path.model"/> 
     <classpath refid="class.path.gui"/> 
     <classpath refid="class.path.jfreereport"/> 
    <classpath path="tmp/${test.jar}"/> 
     <batchtest todir="tmp/rawtestoutput"> 
     <fileset dir="src/test"> 
      <include name="**/*.java"/> 
     <exclude name="**/SessionHelper.java"/> 
     <exclude name="**/TestHelper.java"/> 
     </fileset> 
     </batchtest> 
    <sysproperty key="user" value="tba"/> 
    <sysproperty key="password" value="ibber11"/> 
    </junit> 
    <junitreport todir="tmp"> 
     <fileset dir="tmp/rawtestoutput"/> 
     <report todir="test-reports"/> 
    </junitreport> 
    <fail if="junit.failure" message="Unit test(s) failed. See reports!"/> 
</target> 

Vấn đề duy nhất của tôi bây giờ là, tôi phải lọc ra các lớp thử nghiệm không cần kiểm tra để tránh "Không có phương pháp chạy được". Đó là, các lớp helper và util.

Phải có giải pháp thanh lịch hơn tôi. Một giải pháp có thể là quy ước đặt tên như được đề xuất [JUnit: how to avoid "no runnable methods" in test utils classes.

Lớp trợ giúp không chứa chú thích @Test. Nó phải có thể sử dụng điều này theo một cách nào đó ...

+0

Thử loại trừ **/* Helper.java. –

1

Các trường hợp của các lớp thử nghiệm của bạn cần phải được thực hiện bằng cách nào đó. Bạn có thể tạo một thử nghiệm no-arg để thêm các cá thể kiểm thử được tạo theo một cách khác, có thể hữu ích cho các phép kiểm tra tham số (hoặc trong JUnit 3).

Nhưng tại sao bạn sẽ ngăn chặn hàm tạo tổng hợp no-arg?

1

Có một constructor không có arg cho phép các lớp học thử nghiệm được tổng hợp thành dãy:

TestSuite suite = new TestSuite(); 
suite.add(TestClass.class); 
... 
8

Tôi tin rằng bạn cần một constructor không có args, nhưng nếu bạn không khai báo bất kỳ nhà xây dựng Java sẽ tạo ra một tổng hợp một cho bạn. Bạn có chắc chắn nhiệm vụ không phải là chọn lớp khác; một cái chỉ xảy ra tuân theo quy ước đặt tên bạn đã đặt (*Test hoặc Test*)?

5

Bạn phải có hàm tạo mặc định cho trường hợp thử nghiệm. Nếu không, người chạy không biết cách khởi tạo lớp. Có vẻ như bạn có một hàm tạo với args. Java không tạo hàm tạo mặc định nếu bạn đã có một hàm tạo.

Nói chung, bạn nên tránh các nhà thầu trong các trường hợp thử nghiệm. Nếu bạn muốn khởi tạo, hãy viết một phương thức init và chú thích nó bằng @BeforeClass. Lợi ích là theo dõi stack sẽ sạch hơn nhiều nếu bạn có bất kỳ lỗi nào. Như bạn có thể thấy, dấu vết ngăn xếp của nhà xây dựng thực sự gây nhầm lẫn cho hầu hết mọi người.

5

Eclipse sử dụng triển khai khác để thực thi các trường hợp kiểm tra JUnit4 - nó có Á hậu thử nghiệm riêng. Điều này xảy ra khác với cái được Ant sử dụng - cái mặc định có sẵn trong bản phân phối JUnit, và là lý do cho sự khác biệt được ghi nhận trong hành vi thực hiện của các môi trường trong Ant và Eclipse.

Hãy xem mã nguồn của JUnit 4.3.1, 4.5 và 4.7 (đặc biệt là của các thử nghiệm) cho thấy rằng các lớp thử nghiệm phải có một hàm tạo zero-arg công khai. Lưu ý rằng nhân vật mặc định trong JUnit v4.7 là BlockJUnit4ClassRunner. Bạn sẽ nhận thấy rằng các javadocs (thật đáng tiếc!) Chứa các quy tắc để được theo sau về những gì cấu thành một lớp thử nghiệm được định dạng tốt - một hàm tạo đối số 0 không công khai là một trong số chúng.

+0

Tôi đã suy nghĩ giống như bạn. Rằng nó đã có một cái gì đó để làm với junit3 vs junit4, nhưng theo như tôi có thể nhìn thấy trong stacktrace nó thực sự là một JUnit4TestAdapter có liên quan. –

+0

Vâng, tôi đã xem xét các nguồn của Ant 1.7.1. Trong JUnitTestRunner.java (dòng 386 xuất hiện trong ngăn xếp dấu vết) một cá thể TestSuite được tạo ra, chỉ khi các điều kiện tiên quyết được đáp ứng. –

+0

Rất tiếc, dòng 396 của tôi tạo ra TestSuite trong khi 386 tạo ra JUnit4TestAdapter. –

0

Các lớp bên trong không tĩnh có một hàm tạo ẩn mang lớp bên ngoài làm đối số. Nếu các lớp bên trong của bạn không chia sẻ trạng thái với các lớp bên ngoài, chỉ cần làm cho chúng static.

1

Đối với các phiên bản cũ hơn của junit, nếu bạn có từ "Kiểm tra" trong lớp bên trong của bạn, vấn đề này sẽ xảy ra.

Chúng tôi đã gặp sự cố này trong khi triển khai mẫu phân lớp cho thử nghiệm, đặt tên cho lớp con, ví dụ: FooForTest. Bằng cách đổi tên thành FooSubclass, vấn đề đã được giải quyết.

Xem nhận xét ở trên từ @Vineet Reynolds để biết thêm chi tiết về các phiên bản junit bị ảnh hưởng và tại sao điều này xảy ra đối với kiến ​​nhưng không phải nhật thực.

Hy vọng điều đó sẽ hữu ích!

0

thể là do bạn đang sử dụng Enclosed.class, sau đó các lớp học kèm theo đã được tĩnh

@RunWith(Enclosed.class) 
public class MyClassThatCointaintTestClasses { 
    public static class Class1Test { 
@Test 
public void test1(){ 
} 
@Test 
public void test2(){ 
} 
} 

public static class Class2Test { 
@Test 
public void test21(){ 
} 
@Test 
public void test22(){ 
} 
} 

}

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