Параметризация JUnit3 тестов


(Mykhailo Poliarush) #1

Есть сущуствующие тесты, они к сожанению используют JUnit3 как движок. 
Сейчас нужно прикрутить параметризацию тестов. Но как это сделать пока что не знаю.
Например, в JUnit4 есть специальная аннотация Parameters.
Но как же быть с JUnit3?

@RunWith(Parameterized.class)
public class ParameterizedTest {

    private File file;

    public ParameterizedTest(File file) {
        this.file = file;
    }

    @Test
    public void test1() throws Exception {      }

    @Test
    public void test2() throws Exception {      }

    @Parameters
    public static Collection<Object[]> data() {
        // load the files as you want
        Object[] fileArg1 = new Object[] { new File("path1") };
        Object[] fileArg2 = new Object[] { new File("path2") };

        Collection<Object[]> data = new ArrayList<Object[]>();
        data.add(fileArg1);
        data.add(fileArg2);
        return data;
    }
}


(Леша) #2

А если попробовать в лоб реализовать/скопировать эту аннотацию (@RunWith(Parameterized.class), класс org.junit.runners.Parameterized) в вашем пакете с тестами/фреймворком?

Не знаю, может там какие зависимости могут полезть, но попробовать можно.


(Дмитрий Жарий) #3

Я думаю,

Вы можете читать данные непосредственно из существующего массива
в цикле, внутри тесткейса и без всяких параметризирующих аттрибутов.


(Дмитрий Жарий) #4

Вот как бы я решил эту задачу на Сишарпе

 

{syntaxhighlighter brush: csharp;fontsize: 100; first-line: 1; } [TestClass]
public class ТестСтепениДвойкиУляля
{

    public Dictionary<int, int> ДанныеДляТесткейсаПроверитьСтепеньДвойки = new Dictionary<int, int>
        {
            // степень  // ожидаемое знач
            { 0,           1},
            { 1,           2},
            { 2,           4},
            { 3,           8},
            { 4,           16},
        };

    [TestMethod]
    public void ПроверитьСтепеньДвойки()
    {
        foreach (int key in ДанныеДляТесткейсаПроверитьСтепеньДвойки.Keys)
        {
            ПроверитьСтепеньДвойки(key, ДанныеДляТесткейсаПроверитьСтепеньДвойки[key]);
        }
    }

    public void ПроверитьСтепеньДвойки(int степень, int ожидаемоеЗначение)
    {
        Console.WriteLine("Проверяю, что двойке в степени " + степень + " будет равна " + ожидаемоеЗначение);
        Assert.AreEqual(ожидаемоеЗначение, Math.Pow(2, степень));
    }

}{/syntaxhighlighter}</p><p>&nbsp;</p><p>Прошу заметить, что тесткейс тут:<br>ПроверитьСтепеньДвойки()<br><br><br>А вот это<br>ПроверитьСтепеньДвойки(int степень, int ожидаемоеЗначение)<br><br>Обычный метод, который параметризируется внутри ПроверитьСтепеньДвойки()</p>

(Леша) #5

Да, но это уже будет не JUnit - все преимущества использования JUnit будут потеряны.

Насколько понимаю, то задача стоит с минимальными усилиями параметризировать уже существующие тесты.


(Mykhailo Poliarush) #6

может быть, но я думаю, тут может быть очень много проблем с этим,
пока пытаюсь найти проще вариант


(Mykhailo Poliarush) #7

вариант хороший, надо попробывать, но не сильно идеальный, я бы эту функцию в аннотацию засунул и потом использовал ее ввиде аннотации. 

да есть уже существующие тесты, которые не очень хочется переписывать, хочу сделать что-то на подобии такого

{syntaxhighlighter brush: bash;fontsize: 100; first-line: 1; }public class ParameterizedTest {
@Test
@Parameters(input,expected)
public void test2() throws Exception {
//input and expected variables are used here
}
}{/syntaxhighlighter}

а тестовые данные что были описанны внешне где-то


(Леша) #8

Попробовал повозиться с аннотациями (сделать аналог Parameterized), но довольно быстро понял, что так просто это не получится.

Как вариант можно использовать вариант, предложенный dzhariy, но немножко причесать его. Вот какой вариант видится мне:

1) реализовать свой класс-наследник от TestCase, в нем определить список параметров и переопределить метод runBare(), который завернуть в цикл по параметрам, для доступа к текущему значению параметра использовать протектед переменную.

2) классы тестов наследовать от нашего TestCase, при необходимости переопределить метод для формирования списка параметров

Минусы:

1) цикл по параметрам выполняется до первой ошибки, т.е. если при каком-то значении параметра возникнет ошибка, то последующие итерации выполнены не будут (можно решить подавлением ошибок и репортингом статусов итераций тестов в переопределенном runBare())

2) JUnit-плагин не отображает разбивки по итерациям (как это делает JUnit4 при использовании Parameterized)

Плюсы:

1) остаются все преимущества JUnit

2) минимум изменения в тестах (изменить класс родителя, переопределить метод data() при необходимости)

Делал аналогично использованию Parameterized в JUnit4, но понятно, что можно хранить в качестве текущего значения не массов объектов, а конкретный класс. Подозреваю, что описанные выше проблемы тоже можно решить, но нужно ковыряться с используемыми классами-раннерами.

{syntaxhighlighter brush: java;fontsize: 100; first-line: 1; }public class MyTestCase extends TestCase {
protected Collection<Object[]> parameters = data();
protected Object[] parameter;
protected int iteration;

@Override
public void runBare() throws Throwable {
iteration = -1;
for (Object[] param : parameters) {
this.parameter = param;
iteration++;
super.runBare();
}
}

protected Collection<Object[]> data() {
Collection<Object[]> data = new ArrayList<Object[]>();
data.add(new Object[]{null});
return data;
}
}{/syntaxhighlighter}


Пример теста с иллюстрацией:

{syntaxhighlighter brush: java;fontsize: 100; first-line: 1; }public class MyTest extends MyTestCase {

public void setUp() {
System.err.println("setUp");
}

public void tearDown() {
System.err.println("tearDown");
}

public void testTrue() {
getInfoAboutCurrentIteration();
Assert.assertTrue(true);
}

public void testTrue2() {
getInfoAboutCurrentIteration();
Assert.assertTrue(false);
}

private void getInfoAboutCurrentIteration() {
String parameterDescription = "(length: " + parameter.length + ")";
for (Object obj : parameter) {
parameterDescription = parameterDescription + obj.toString();
}
System.err.println(String.format(" - - - Iteration: %s, parameter: %s", iteration, parameterDescription));
}

@Override
protected Collection<Object[]> data() {
Collection<Object[]> data = new ArrayList<Object[]>();
data.add(new Object[]{1});
data.add(new Object[]{2});
data.add(new Object[]{3});
return data;
}
}
{/syntaxhighlighter}


(Mykhailo Poliarush) #9

адаптированный вариант выглядит хорошо, но как-то много кда вставляется в одном тесте

все равно, хочу попробовать вариант с вынесением данных в внешний источник, типа файла, и его читать от туда с помощью, какого-то класса и использовать этот класс в аннотации. 

думаю, придется заглянуть внутырь junit 4, посмотреть на их реализацию и от нее оттакливаться

все равно спасибо за советы! очень благодарен.


(Леша) #10

В коде класса-теста вставляется только переопределенный метод data() - по аналогии с Parameterized в JUnit4.