2012-08-02 148 views
2

使用JUnit4,我想要做的是能夠測試一組不同的java項目,它們都做同樣的事情,但不必寫出測試爲了測試每個項目,我想知道是否可以編寫一個可以在多個類上運行的單個測試?是否可以使用單個測試測試多個類

如果這不可能使用JUnit4,是否有可能以任何其他方式做到這一點?

我知道這個心不是正確的,但是這僅僅是給的我在說什麼的簡單說明:

+0

如果項目「都做同樣的事情」,你應該重構的時候和移動通用功能集成到一個額外的項目。 *該項目可以被測試。 – 2012-08-02 13:29:34

回答

3

您可以使用JUnit的@Parameterized。

@RunWith(Parameterized.class) 
public class BehaviorTest { 
    @Parameters 
    public static Collection<Object[]> classesAndMethods() { 
     List<Object[]> list = new ArrayList<Object[]>(); 
     list.add(new Object[]{ Foo.class, Foo.class.getMethod("foo") }); 
     return list; 
    } 

    private Class clazz; 
    private Method method; 

    public BehaviorTest(Class clazz, Method method) { 
     this.clazz = clazz; 
     this.method = method; 
    } 

    @Test 
    public void testBehavior() { 
     // Do stuff 
    } 
} 
+0

我會稍後再試,但如果這樣做的話,它正是我尋找的東西的類型......謝謝:) – 2012-08-02 13:40:39

1

如何像...

for(Class cls: new Class[] { Class1.class, ... }) 
    assertEquals(1, nameOfMethod.invoke(cls.newInstance())); 
+0

有沒有辦法從java文件中獲取.class,因爲我不想硬編碼所有的.class文件,因爲它們會經常變化? – 2012-08-02 16:06:22

+0

你需要一些方法來確定你想要測試的類。例如,您可以使用反射庫來搜索實現接口的所有類。 – 2012-08-02 16:24:21

+0

,因爲我有一個我想測試的所有java類的列表,我將它們傳遞給測試'files = retrieveFiles.listFilesForFolder(folder);對於(File currentFile:files){ // list.add(new Object [] {currentFile.toString()。class,currentFile.toString()。class}); }'但我只需要獲取每個java文件的.class文件 – 2012-08-02 16:28:07

1

當然。對此沒有技術限制。但這不是可取的。有一個很好的理由,他們稱之爲單元測試。

如果您即將對多個類使用相同的測試,那麼這通常意味着您的應用程序中有重複的代碼。


測試類是普通的Java類,所以你可以使用繼承來實現你心目中:包含實際的測試和子(試驗 - )類,做一些設置基地(測試)類,IAW ,用要測試的不同類的實例初始化測試。你甚至可以使用反射來創建實例和方法對象。

這可能是一個解決方案,如果你不得不準備單元測試的任務,你期望同一個任務幾十個不同的類。但對於大多數其他情況,我寧願複製測試方法,然後創建複雜的測試類。

+0

對不起,我應該提到它是用於測試學生項目,所以所有的項目基本上會做同樣的事情,它不是測試一個具有多個類的項目做同樣的事情......它將作爲一個單一的單一類的單元測試,但對於多個項目 – 2012-08-02 13:36:32

0

對不起,跳到這麼晚了。有了類似的需求,我已經開發了一些演示和培訓,演示了重構後隨着時間的推移給定班級的變化。因此,測試是相同的,但類本身改變。每個版本都包含在不同的包中。類名保持不變。這聽起來與OP所面臨的類似。

我發現參數化的解決方案很麻煩。我使用了兩種解決方案。它們都是用Groovy編寫的,但下面的第二個例子應該可以作爲純Java解決方案來實現。

以下是第一條:

public class ItemTest { 
    def defaultConstructedClasses = [ 
     new com.groovifyingjava.essentialgroovification.Item() 
     ,new com.groovifyingjava.rewriteequals.Item() 
     ,new com.groovifyingjava.removesemicolons.Item() 
     ,new com.groovifyingjava.removeparentheses.Item() 
     ,new com.groovifyingjava.removeaccessors.Item() 
     ,new com.groovifyingjava.removeconstructors.Item() 
     ,new com.groovifyingjava.removeimports.Item() 
     ,new com.groovifyingjava.removereturn.Item() 
     ,new com.groovifyingjava.clarifyidentityequality.Item() 
     ,new com.groovifyingjava.coercetypes.Item() 
     ,new com.groovifyingjava.defaultaccessmodifiers.Item() 
     ,new com.groovifyingjava.eachiteration.Item() 
     ,new com.groovifyingjava.fieldaccessnotation.Item() 
     ,new com.groovifyingjava.namedparameters.Item() 
     ,new com.groovifyingjava.optionaldatatyping.Item() 
     ,new com.groovifyingjava.safelynavigate.Item() 
     ,new com.groovifyingjava.simplifylistmapsetcreation.Item() 
     ,new com.groovifyingjava.stringinterpolation.Item() 
     ,new com.groovifyingjava.useelvisoperator.Item() 
     ,new com.groovifyingjava.useequalsoperator.Item() 
     ,new com.groovifyingjava.usemathoperators.Item() 
     ,new com.groovifyingjava.useprintln.Item() 
    ] 

    def overloadedConstructorArgs = [itemId: "14-101", manufacturer: "Raleigh", model: "Superbe Roadster", cost: 179.89, quantityOnHand: 10] 

    def overloadedConstructedClasses = [ 
     new com.groovifyingjava.essentialgroovification.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.rewriteequals.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.removesemicolons.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.removeparentheses.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.removeaccessors.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.removeconstructors.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.removeimports.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.removereturn.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.clarifyidentityequality.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.coercetypes.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.defaultaccessmodifiers.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.eachiteration.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.fieldaccessnotation.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.namedparameters.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.optionaldatatyping.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.safelynavigate.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.simplifylistmapsetcreation.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.stringinterpolation.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.useelvisoperator.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.useequalsoperator.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.usemathoperators.Item(overloadedConstructorArgs) 
     ,new com.groovifyingjava.useprintln.Item(overloadedConstructorArgs) 
    ] 

    @Test public void canCreateDefaultInstance() { 
     for(def item in defaultConstructedClasses) { 
      assertNull "Default construction of class ${item.class.name} failed to properly initialize field.", item.itemId 
      assertNull "Default construction of class ${item.class.name} failed to properly initialize field.", item.manufacturer 
      assertNull "Default construction of class ${item.class.name} failed to properly initialize field.", item.model 
      assertNull "Default construction of class ${item.class.name} failed to properly initialize field.", item.cost 
      assertEquals "Default construction of class ${item.class.name} failed to properly initialize field.", 0, item.quantityOnHand 
      assertEquals "Default construction of class ${item.class.name} failed to properly initialize field.", BigDecimal.ZERO, item.inventoryValue as BigDecimal 
     } 
    } 

    @Test public void canCreateInstancesFromOverloadedConstructor() { 
     for(def item in overloadedConstructedClasses) { 
      assertEquals "Instantiation of class ${item.class.name} using overloaded constructor failed to properly initialize field.","14-101", item.itemId 
      assertEquals "Instantiation of class ${item.class.name} using overloaded constructor failed to properly initialize field.", "Raleigh", item.manufacturer 
      assertEquals "Instantiation of class ${item.class.name} using overloaded constructor failed to properly initialize field.", "Superbe Roadster", item.model 
      assertEquals "Instantiation of class ${item.class.name} using overloaded constructor failed to properly initialize field.", 179.89, item.cost 
      assertEquals "Instantiation of class ${item.class.name} using overloaded constructor failed to properly initialize field.", 10, item.quantityOnHand 
      assertEquals "Instantiation of class ${item.class.name} using overloaded constructor failed to properly initialize field.", new BigDecimal("1798.90"), item.inventoryValue as BigDecimal 
     } 
    } 
} 

這工作得很好,是很容易實現。它使用Groovy duck打字來測試每個類。缺點是Eclipse中的junit控制檯將顯示最後一次測試運行。這可能不是什麼大不了的事。此外,它會在失敗的測試中停止執行。請注意,我將該類名稱包含在斷言消息字符串中。這可以很容易地識別失敗的班級。

第二個版本需要一個抽象測試類,並且在每個包中都有一個測試類,與每個測試類的包相對應。這些只不過是存根(stub),但允許你謹慎地運行測試或在一個套件中運行測試。

public abstract class CommonItemTest { 
    def overloadedConstructorArgs = [itemId: "14-101", manufacturer: "Raleigh", model: "Superbe Roadster", cost: 179.89, quantityOnHand: 10] 

    @Test public void canCreateDefaultInstance() { 
     def item = defaultConstructedClass 

     assertNull "Default construction of class ${item.class.name} failed to properly initialize field. Expected itemId to be null.", item.itemId 
     assertNull "Default construction of class ${item.class.name} failed to properly initialize field. Expected manufacturer to be null.", item.manufacturer 
     assertNull "Default construction of class ${item.class.name} failed to properly initialize field. Expected model to be null.", item.model 
     assertNull "Default construction of class ${item.class.name} failed to properly initialize field. Expected cost to be null.", item.cost 
     assertEquals "Default construction of class ${item.class.name} failed to properly initialize field. Expected quantityOnHand to be zero.", 0, item.quantityOnHand 
     assertEquals "Default construction of class ${item.class.name} failed to properly initialize field. Expected inventoryValue to be zero.", BigDecimal.ZERO, item.inventoryValue as BigDecimal 
    } 

    @Test public void canCreateInstancesFromOverloadedConstructor() { 
     def item = overloadedConstructedClass 

     assertEquals "Instantiation of class ${item.class.name} using overloaded constructor failed to properly initialize field.","14-101", item.itemId 
     assertEquals "Instantiation of class ${item.class.name} using overloaded constructor failed to properly initialize field.", "Raleigh", item.manufacturer 
     assertEquals "Instantiation of class ${item.class.name} using overloaded constructor failed to properly initialize field.", "Superbe Roadster", item.model 
     assertEquals "Instantiation of class ${item.class.name} using overloaded constructor failed to properly initialize field.", 179.89, item.cost 
     assertEquals "Instantiation of class ${item.class.name} using overloaded constructor failed to properly initialize field.", 10, item.quantityOnHand 
     assertEquals "Instantiation of class ${item.class.name} using overloaded constructor failed to properly initialize field.", new BigDecimal("1798.90"), item.inventoryValue as BigDecimal 
    } 

    abstract Object getDefaultConstructedClass(); 
    abstract Object getOverloadedConstructedClass(); 
} 

和實現...

public class ItemTest extends CommonItemTest { 
    public Object getDefaultConstructedClass() { 
     return new Item() 
    } 
    public Object getOverloadedConstructedClass() { 
     return new Item(overloadedConstructorArgs) 
    } 
} 
相關問題