2010-05-27 2 views
2

Я работал над Java-приложением, где мне нужно использовать JUnit для тестирования. Я изучаю это, когда иду. До сих пор я считаю, что это полезно, особенно при использовании в сочетании с плагином Eclipse JUnit.JUnit для функций с Void Возвращаемые значения

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

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

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

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 
{ 
    // ... 
} 

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

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 тесты

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

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, поэтому я уверен, что есть доступные инструменты, которые могут облегчить этот процесс. Благодаря!

+0

Недействительные функции обычно имеют побочные эффекты, так что вы можете проверить их? –

ответ

3

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

Однако:

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

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

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

@Test(expected=IndexOutOfBoundsException.class) 
public void testIndexOutOfBoundsException() { 
    ArrayList emptyList = new ArrayList(); 
    Object o = emptyList.get(0); 
} 
+0

Я переписал свои тесты, чтобы использовать этот формат. Это намного проще. Благодаря! – RobotNerd

+0

Имейте в виду, что если вы используете этот синтаксис, тест пройдет, если какой-либо из кода, запущенного в тесте, бросил IndexOutOfBoundsException. Иногда это не проблема, поскольку у вас уже есть тестовые примеры, которые охватывают не исключительные случаи, но не делайте этого для длительных тестов. Если вы используете JUnit 4.7. попробуйте правило ExpectedException: http://www.infoq.com/news/2009/07/junit-4.7-rules – NamshubWriter

1

Похоже, вы перепробовали большую часть 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 потерпит неудачу тест.

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

2

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

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

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

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

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

0

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

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 бы acutally проверить, если вы звоните targetFunction сделали бы ожидаемые изменения - скажем, в таблице базы данных, возвращая истинным или ложным.

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

Cheers, Markus

Смежные вопросы