0

我正在实现一些基本的排序算法(出于学习的目的),并想为它们编写单元测试。所有排序程序都有以下通用 api

...
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);
    }   

}
4

3 回答 3

1

用于接口

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();
    }

}

使用反射它有点混乱,但仍然可行。我没有测试过这段代码,所以可能有几个错误,但过去曾使用过这种方法。在 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;
    }

}
于 2013-07-16T06:31:06.210 回答
0

正如@BevynQ 所说,如果您使您的方法成为非静态的,并且您实现了一个接口(Sorter下面称为),那么您将使自己的生活变得更加轻松。您可以轻松使用Parameterized。这是如何使用它的一个非常简单的示例,(未经测试,未经编译)

@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));
  }
}
于 2013-07-16T06:53:12.190 回答
0

为什么不这样呢?

@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 种不同的排序来测试。所以应该不错。

否则,您可以在 Array 中声明所有排序类并使用 Class 属性加载。

于 2013-07-16T06:23:59.030 回答