t.me/atinfo_chat Telegram группа по автоматизации тестирования

Параметризация 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;
}

}

</p><p><!--break--></p>

(Леша) #2

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

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


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

Я думаю,

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


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

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

 

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

    public Dictionary&lt;int, int&gt; ДанныеДляТесткейсаПроверитьСтепеньДвойки = new Dictionary&lt;int, int&gt;
        {
            // степень  // ожидаемое знач
            { 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.