在java/junit中组织单元测试,以便使用公共api测试类

在java/junit中组织单元测试,以便使用公共api测试类,java,junit,organization,Java,Junit,Organization,我正在实现一些基本的排序算法(为了学习),并想为它们编写单元测试 ... public static void sort(Comparable[] a); ... public static boolean isSorted(Comparable[] a); ... public static boolean isSorted(Comparable[] a),int from ,int to; ... 因此,我编写了以下测试来测试SelectionSort中的isSorted()方法 publ

我正在实现一些基本的排序算法(为了学习),并想为它们编写单元测试

...
public static void sort(Comparable[] a);
...
public static boolean isSorted(Comparable[] a);
...
public static boolean isSorted(Comparable[] a),int from ,int to;
...
因此,我编写了以下测试来测试SelectionSort中的isSorted()方法

public class SelectionSortTests {
        String[] a ;    

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

    @Test
    public void arraySortedSingleElement(){
        a = new String[]{"A"};
        Assert.assertTrue(SelectionSort.isSorted(a));
    }

    @Test
    public void arraySortedDistinctElements(){
        a = new String[]{"A","B","C","D"};
        Assert.assertTrue(SelectionSort.isSorted(a));
    }
    @Test
    public void arrayNotSorted(){
        a = new String[]{"A","B","C","B"};
        Assert.assertFalse(SelectionSort.isSorted(a));
    }
...
}
现在我觉得,如果我为InsertionSort、ShellSort等编写测试,它们看起来都是一样的。只有被测试的类的名称会改变

那么,我应该如何组织测试呢?一个套件是答案还是我可以使用反射做得更好?可能是编写一个驱动程序,我可以在其中添加要测试的类的名称列表,驱动程序通过将类名传递给它来调用运行公共单元测试

我意识到这是一种常见的情况。想知道如何在没有唾沫或胶带的情况下处理这个问题

更新: 感谢@BevinQ和@Matthew Farwell,我尝试使用参数化单元测试来解决这个问题。 使用反射调用静态方法。。 似乎有效:)但我认为它仍然可以重构以避免重复代码

@RunWith(Parameterized.class)
public class ParameterizedSortTests {
    private Class classToTest;
    private Method methodToTest;

    public ParameterizedSortTests(String packageName,String classToTest) {
        super();
        try {
            this.classToTest = Class.forName(packageName+"."+classToTest);
        } catch (ClassNotFoundException e) {
            System.out.println("failed to get class!!");
            e.printStackTrace();
        }

    }

    //method return collection of class names to be tested
    @Parameterized.Parameters
    public static  List<Object[]> classesToTest(){
        return Arrays.asList(new Object[][]{ 
                {"elemsorts","SelectionSort"} ,
                {"elemsorts","InsertionSort"} 
        });
    }


    public void setMethod(String method,Class...args){
        try {
            this.methodToTest = this.classToTest.getMethod(method, args);
        } catch (SecurityException e) {

            e.printStackTrace();
        } catch (NoSuchMethodException e) {

            e.printStackTrace();
        }
    }

    @Test
    public void arrayIsSorted(){
        setMethod("isSorted",Comparable[].class);
        String[] a = new String[]{"A","B","C","D"};
        Boolean arraySorted = null;
        try {
            arraySorted = (Boolean)this.methodToTest.invoke(null, new Object[]{a});
            System.out.println(this.methodToTest+"returned :"+arraySorted);
        } catch (IllegalArgumentException e) {

            e.printStackTrace();
        } catch (IllegalAccessException e) {

            e.printStackTrace();
        } catch (InvocationTargetException e) {

            e.printStackTrace();
        }

        Assert.assertTrue(arraySorted);
    }

    @Test
    public void arrayIsNotSorted(){
        setMethod("isSorted",Comparable[].class);
        String[] a = new String[]{"A","B","C","B"};
        Boolean arraySorted = null;
        try {
            arraySorted = (Boolean)this.methodToTest.invoke(null, new Object[]{a});
            System.out.println(this.methodToTest+"returned :"+arraySorted);
        } catch (IllegalArgumentException e) {

            e.printStackTrace();
        } catch (IllegalAccessException e) {

            e.printStackTrace();
        } catch (InvocationTargetException e) {

            e.printStackTrace();
        }
        //System.out.println("arraySorted="+arraySorted);
        Assert.assertFalse(arraySorted);
    }   

}
@RunWith(参数化的.class)
公共类参数化SortTests{
私有类类测试;
私有方法测试;
公共参数化SortTests(字符串packageName、字符串classToTest){
超级();
试一试{
this.classToTest=Class.forName(packageName+“+classToTest);
}catch(classnotfounde异常){
System.out.println(“未能获取类!!”;
e、 printStackTrace();
}
}
//方法返回要测试的类名集合
@参数化。参数化
公共静态列表classesToTest(){
返回Arrays.asList(新对象[][]{
{“elemsorts”,“SelectionSort”},
{“elemsorts”,“InsertionSort”}
});
}
公共void setMethod(字符串方法、类…参数){
试一试{
this.methodToTest=this.classToTest.getMethod(方法,args);
}捕获(安全异常e){
e、 printStackTrace();
}捕获(无此方法例外){
e、 printStackTrace();
}
}
@试验
公共无效数组排序(){
setMethod(“isSorted”,可比[]类);
字符串[]a=新字符串[]{“a”、“B”、“C”、“D”};
布尔数组排序=null;
试一试{
arraySorted=(布尔)this.methodToTest.invoke(null,新对象[]{a});
System.out.println(this.methodToTest+“返回:”+arraySorted);
}捕获(IllegalArgumentException e){
e、 printStackTrace();
}捕获(非法访问例外e){
e、 printStackTrace();
}捕获(调用TargetException e){
e、 printStackTrace();
}
Assert.assertTrue(arraySorted);
}
@试验
公共无效数组未排序(){
setMethod(“isSorted”,可比[]类);
字符串[]a=新字符串[]{“a”、“B”、“C”、“B”};
布尔数组排序=null;
试一试{
arraySorted=(布尔)this.methodToTest.invoke(null,新对象[]{a});
System.out.println(this.methodToTest+“返回:”+arraySorted);
}捕获(IllegalArgumentException e){
e、 printStackTrace();
}捕获(非法访问例外e){
e、 printStackTrace();
}捕获(调用TargetException e){
e、 printStackTrace();
}
//System.out.println(“arraySorted=“+arraySorted”);
Assert.assertFalse(arraySorted);
}   
}

为什么不做这样的事情

@Test
public void arraySortedDistinctElements(){
    a = new String[]{"A","B","C","D"};
    Assert.assertTrue(SelectionSort.isSorted(a));
    Assert.assertTrue(InsertionSort.isSorted(a));
    Assert.assertTrue(QuickSort.isSorted(a));
}
我不认为你有超过10种不同的分类需要测试。所以它应该是好的

另外,您可以在数组中声明所有排序类,并使用类属性进行加载。

对于接口

public abstract class AbstractSortTests {
    String[] a ;    

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

   protected abstract Sorter getSorter();

    @Test
    public void arraySortedSingleElement(){
        a = new String[]{"A"};
        Assert.assertTrue(getSorter().isSorted(a));
    }

    @Test
    public void arraySortedDistinctElements(){
        a = new String[]{"A","B","C","D"};
        Assert.assertTrue(getSorter.isSorted(a));
    }
...
}

public class SelectionSortTests extends AbstractSortTests {

    protected Sorter getSorter(){
        return SelectionSort.getInstance();
    }

}

public class QuickSortTests extends AbstractSortTests {

    protected Sorter getSorter(){
        return QuickSort.getInstance();
    }

}
使用反射,这是一个有点混乱,但仍然可以做到。我还没有测试过这段代码,所以可能已经测试过了 有几个bug,但在过去使用过这种方法。在99%的情况下,使用接口将是首选方法

public abstract class AbstractSortTests {
    String[] a ;    

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

   protected abstract Sorter getSorter();

    @Test
    public void arraySortedSingleElement() throws Exception{
        a = new String[]{"A"};
        Assert.assertTrue(executeMethod(getSorterClass(), "isSorted", a);
    }

    @Test
    public void arraySortedDistinctElements() throws Exception{
        a = new String[]{"A","B","C","D"};
        Assert.assertTrue(executeMethod(getSorterClass(), "isSorted", a);
    }

    private void executeMethod(Class<?> sortClass, String methodName, String[] values) throws Exception{
        return sortClass.getDeclaredMethod(methodName, new Class[]{String[].class}).invoke(null, new Object[]{values});
    }
...
}

public class SelectionSortTests extends AbstractSortTests {

    protected Class<?> getSorterClass(){
        return SelectionSort.class;
    }

}
公共抽象类AbstractSortTests{
字符串[]a;
@之后
public void tearDown()引发异常{
a=零;
}
受保护的抽象分类器getSorter();
@试验
public void arraySortedSingleElement()引发异常{
a=新字符串[]{“a”};
Assert.assertTrue(executeMethod(getSortrClass(),“isSorted”,a);
}
@试验
public void ArraySortedDistincElements()引发异常{
a=新字符串[]{“a”、“B”、“C”、“D”};
Assert.assertTrue(executeMethod(getSortrClass(),“isSorted”,a);
}
私有void executeMethod(类sortClass、字符串methodName、字符串[]值)引发异常{
返回sortClass.getDeclaredMethod(methodName,新类[]{String[].Class}).invoke(null,新对象[]{values});
}
...
}
公共类SelectionSortTests扩展了AbstractSortTests{
受保护类GetSortrClass(){
返回SelectionSort.class;
}
}

正如@BevynQ所说的,如果你将方法变成非静态的,并且你实现了一个接口(下面称为
Sorter

@RunWith(参数化的.class)
公共类分拣机{
@参数
公共静态可编辑数据(){
返回Arrays.asList(新对象[][]{
{new SelectionSort()},
{new BubbleSort()}
});
}
专用最终分拣机
公共分拣机测试(分拣机分拣机){
this.sorter=分拣机;
}
@试验
公共无效数组排序SingleElement(){
字符串[]a=新字符串[]{“a”};
Assert.assertTrue(sorter.isSorted(a));
}
@试验
public void arraysorteddinstinctelements(){
字符串[]a=新字符串[]{“a”、“B”、“C”、“D”};
Assert.assertTrue(sorter.isSorted(a));
}
@试验
public void arrayNotSorted(){
字符串[]a=新字符串[]{“a”、“B”、“C”、“B”};
Assert.assertFalse(sorter.isSorted(a));
@RunWith(Parameterized.class)
public class SorterTest {
  @Parameters
  public static Iterable<Object[]> data() {
    return Arrays.asList(new Object[][] {
      { new SelectionSort() },
      { new BubbleSort() }
    });
  }

  private final Sorter sorter

  public SorterTest(Sorter sorter) {
    this.sorter = sorter;
  }

  @Test
  public void arraySortedSingleElement(){
    String[] a = new String[]{"A"};
    Assert.assertTrue(sorter.isSorted(a));
  }

  @Test
  public void arraySortedDistinctElements(){
    String[] a = new String[]{"A","B","C","D"};
    Assert.assertTrue(sorter.isSorted(a));
  }

  @Test
  public void arrayNotSorted(){
    String[] a = new String[]{"A","B","C","B"};
    Assert.assertFalse(sorter.isSorted(a));
  }
}