JUnit для функций с пустыми возвращаемыми значениями - PullRequest
2 голосов
/ 27 мая 2010

Я работал над приложением Java, где я должен использовать JUnit для тестирования. Я учу это, как я иду. Пока что я нахожу это полезным, особенно когда используется вместе с плагином Eclipse JUnit.

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

Общие возвращаемые значения

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

public enum UnitTestReturnValues
{
    noException,
    unexpectedException
    // etc...
}

Обобщенный тест

Допустим, написан юнит-тест для:

public class SomeClass
{
    public void targetFunction (int x, int y)
    {
        // ...
    }
}

Будет создан тестовый класс JUnit:

import junit.framework.TestCase;
public class TestSomeClass extends TestCase
{
    // ...
}

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

public class TestSomeClass extends TestCase
{
    private UnitTestReturnValues callTargetFunction (int x, int y)
    {
        UnitTestReturnValues outcome = UnitTestReturnValues.noException;
        SomeClass testObj = new SomeClass ();
        try
        {
            testObj.targetFunction (x, y);
        }
        catch (Exception e)
        {
            UnitTestReturnValues.unexpectedException;
        }
        return outcome;
    }
}

JUnit Tests

Функции, вызываемые JUnit, начинаются со строчной буквы «test» в имени функции, и они терпят неудачу при первом неудачном утверждении. Чтобы запустить несколько тестов для целевой функции выше, она будет записана в виде:

public class TestSomeClass extends TestCase
{
    public void testTargetFunctionNegatives ()
    {
        assertEquals (
            callTargetFunction (-1, -1),
            UnitTestReturnValues.noException);
    }

    public void testTargetFunctionZeros ()
    {
        assertEquals (
            callTargetFunction (0, 0),
            UnitTestReturnValues.noException);
    }

    // and so on...
}

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

Ответы [ 4 ]

3 голосов
/ 27 мая 2010

Это правда, что если вы используете JUnit 3 и тестируете, генерируется ли конкретное исключение в методе, вам нужно использовать что-то вроде шаблона try-catch, который вы определили выше.

Тем не менее:

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

Я также вообще против добавления кода и добавления сложности, если этого можно избежать; Я не думаю, что это обременительно - помещать попытку / ловушку в данный тест, когда он проверяет исключения.

2) Переключитесь на JUnit 4! Это позволяет легко проверить ожидаемые исключения:

@Test(expected=IndexOutOfBoundsException.class)
public void testIndexOutOfBoundsException() {
    ArrayList emptyList = new ArrayList();
    Object o = emptyList.get(0);
}
2 голосов
/ 27 мая 2010

Если у вас есть такая возможность, вам следует перейти на JUnit 4.x.

Тогда ваш первый пример можно переписать так:

@Test(expected=RuntimeException.class)
public void testTargetFunction() {
   testObj.targetFunction (x, y);
}

Преимущество здесь в том, что вы можете удалить метод private UnitTestReturnValues callTargetFunction (int x, int y) и использовать встроенную поддержку JUnit для ожидания исключений.

Вы должны также проверить определенные исключения вместо этого.

1 голос
/ 27 мая 2010

Похоже, вы переопределили большую часть JUnit :) В общем, вам не нужно это делать. Вы просто вызываете функцию, которую хотите вызвать, и сравниваете результаты. Если он выдаст исключение, JUnit поймает, если для вас, и провалит тест. Если вы ожидаете исключения, либо вы можете использовать явную аннотацию, если вы используете JUnit 4, либо вы можете использовать следующий шаблон:

public void testThrows()
{
    try {
        obj.DoSth(); //this should throw MyException
        assertFail("Expected exception");
    } catch (MyException e) {
        //assert the message etc
    }
}

еще раз, если obj.DoSth () выдает другое исключение, JUnit не пройдет тест.

Итак, подведу итог, боюсь, я считаю, что ваш подход слишком сложен, извините.

0 голосов
/ 27 мая 2010

пожалуйста, поправьте меня, если я ошибаюсь. Как я понял из предоставленного кода, вы только проверяете, может ли быть исключение при выполнении функции. Но вы на самом деле не проверяете, правильно ли вызванные функции «работают», если только исключение не будет единственным способом завершить работу в случае ошибки. Я предлагаю написать дополнительные тесты, подобные этому:

public void testTargetFunctionSomeValue()  {
  int someValue = 0;
  callTargetFunction(someValue, someValue);
  assertTrue(verifyTargetFunction(someValue, someValue));
}

public boolean verifyTargetFucntion(int someValue, int someValue) {
 // verify that execution of targetFunction made expected changes.
  . . . . . 
}

и verifyTargetFunction будет автоматически проверять, вызвал ли бы вызов targetFunction ожидаемые изменения - скажем, в таблицу базы данных, вернув true или false.

Надеюсь, это поможет.

Ура, Markus

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...