Приложение EnglishTesting создано для тестирования английского языка. Оно выводит вопрос - Английское слово и запрашивает от пользователя перевод. Слова хранятся в БД(mysql). Для того чтобы приложение заработало Вам необходимо :
Также Вам необходимо скачать JDBC driver для MYSQL и прописать его в конфигурационном файле:
CLASSPATH=./:/home/JavaClasses:/home/JavaClasses/EnglishTesting.jar:/home/JavaClasses/mysql-connector-java-5.1.14-bin.jar
После всех корректных настроек(также проверьте правильность подключения драйвера в проекте) использовать приложение можно следующим образом:
# java userconsole.ViewTesting
Вопрос № 1
howling
Перевод :
....
Дата: Sat Feb 05 19:19:08 MSK 2011
Результат 50%
Правильных ответов 2 из 4
Ошибок 2
Неправильный ответ на вопрос № 2
Слово perform
Ваш ответ .
Правильный ответ [выполнять, исполнять, делать]
...
Исходный код проекта EnglishTesting.tar.gz.
Теперь покроем юнит-тестами созданный класс EnglishTesting.java. Для того, чтобы протестировать методы( классы), которые в свою очередь зависят от других классов необходимо использовать заглушки (stub).
Так как класс EnglishTesting зависит от класса DataConnection, а нам нужно протестировать именно работоспособность EnglishTesting, то мы с помощью интерфейса DataConnection в тестовом классе EnglishTestingTest создадим заглушку на DataConnection. Таким образом, всегда можно протестировать классы независимо друг от друга - в этом и есть суть юнит-тестирования.
Начнем с метода, который использует класс DataConnection в качестве переменной. Это метод getEngWord():
public class EnglishTesting { ... public String getEngWord(DataConnection data){ String englishWord; englishWord = data.returnRandomWord(); return englishWord; } ... }
Этот метод просто возвращает слово, полученное от объекта data методом returnRandomWord().
Теперь создадим заглушку StubDBconnect :
public class StubDBconnect implements DataConnection{ public String returnRandomWord() { return "Hello"; } public ArrayListreturnAnswersByWord(String englishWord) { ArrayList answersList = new ArrayList (); answersList.add("привет"); return answersList; } }
Теперь наш Test Case c одним тестовым методом будет выглядеть следующим образом:
package testing; import connection.DataConnection; import java.util.ArrayList; import org.junit.Test; import static org.junit.Assert.*; public class EnglishTestingTest { /** * Stub class - Data Connection */ public class StubDBconnect implements DataConnection{ public String returnRandomWord() { return "Hello"; } public ArrayListreturnAnswersByWord(String englishWord) { ArrayList answersList = new ArrayList (); answersList.add("привет"); return answersList; } } @Test public void testGetEnglishWord(){ StubDBconnect data = new StubDBconnect(); EnglishTesting test = new EnglishTesting(); String word = test.getEngWord(data); assertEquals("Hello",word); } }
Таким образом в assertEquals() мы сравниваем эталон - "Hello" - то тестовое слово , которое всегда возвращает заглушка с тем, что получили методом getEngWord(DataConnection data).
В предыдущей статье уже говорилось о возможных вариантах проверок.
Аналогично рассмотрим следующий метод checkAnswer() класса EnglishTesting, который необходимо проотестировать:
public class EnglishTesting { ... boolean checkAnswer(String englishWord, String russianWord,DataConnection data){ ArrayListanswersList = data.returnAnswersByWord(englishWord); return answersList.contains(russianWord); } ... }
Данный метод также использует public метод returnAnswersByWord() объекта класса DataConnection. Поэтому для создания unit-теста мы опять будем использовать заглушку:
public class EnglishTestingTest { @Test public void testCheckAnswer(){ StubDBconnect data = new StubDBconnect(); EnglishTesting test = new EnglishTesting(); assertTrue(test.checkAnswer("Hello", "привет", data)); } ... }
Дадим всем методам класса EnglishTesting пакетный доступ для того, чтобы их можно было покрыть unit-тестами. Для тех, которые используются в Main классе дадим доступ public.
Теперь рассмотрим внутренний метод calcPercent() он использует 2 переменные объекта countQuests и skill и возвращает процент правильных ответов пользователя в качестве строки, например, "50%"
public class EnglishTesting { ... String calcPercent(){ if (countQuests>0){ double percent = skill.doubleValue()/countQuests.doubleValue(); NumberFormat percentFormat = NumberFormat.getPercentInstance(); percentFormat.setMaximumFractionDigits(1); String result = percentFormat.format(percent); return result; } else { return "100%"; } } ... }
Для создания теста этого метода заглушка, нам уже не нужна , но необходимо задать тестовые значения переменных объекта. А именно:
public class EnglishTestingTest { ... @Test public void testCalcPercent(){ EnglishTesting test = new EnglishTesting(); //Test data test.countQuests=4; test.skill = 2; assertEquals("50%", test.calcPercent()); } ... }
После вынесения объектов data и test в метод @Before наш Test Case примет следующий вид :
package testing; import org.junit.Before; import connection.DataConnection; import java.util.ArrayList; import org.junit.Test; import static org.junit.Assert.*; /** * JUnit tests for EnglishTesting.java * Testing logic which works with DB * Testing logic methods getResults(), calcPercent(),calcSkill() * @author Shpatserman Maria */ public class EnglishTestingTest { /** * Stub class - Data Connection */ public class StubDBconnect implements DataConnection{ public String returnRandomWord() { return "Hello"; } public ArrayListreturnAnswersByWord(String englishWord) { ArrayList answersList = new ArrayList (); answersList.add("привет"); return answersList; } } private StubDBconnect data; private EnglishTesting test; @Before public void instantiate() { test = new EnglishTesting(); data = new StubDBconnect(); } //Logic tests @Test public void testCalcPercentNullQuestions(){ test.countQuests=0; assertEquals("100%",test.calcPercent()); } @Test public void testCalcPercent(){ //Test data test.countQuests=4; test.skill = 2; assertEquals("50%", test.calcPercent()); } @Test public void testCalcSkillIncrement(){ //Test data test.countQuests=0; test.skill = 0; //CorrectAnswer test.calcSkill("Hello", "привет", 1, data); //Check skills assertTrue(test.skill==1); } @Test public void testCalcSkillIncrementErrors(){ //Test data test.countQuests=0; test.errors = 0; //IncorrectAnswer test.calcSkill("Hello", "пока", 1, data); //Check errors assertTrue(test.errors==1); } @Test public void testGetResultsExcelent(){ //Test data test.errors = 0; test.countQuests =1; test.skill=1; String result = test.getResults(); String expect = "Великолепно! \n"+ "Результат 100%\n"+ "Правильных ответов 1 из 1"; assertEquals(expect, result); } @Test public void testGetResultsGood(){ //Test data test.errors = 1; test.countQuests =2; test.skill=1; test.improperAnswers=""; String result = test.getResults(); String expect = "Результат 50%\n"+ "Правильных ответов 1 из 2\n"+ "Ошибок 1\n"; assertEquals(expect, result); } //Work with Data @Test public void testGetEnglishWord(){ //StubDBconnect data = new StubDBconnect(); String word = test.getEngWord(data); assertEquals("Hello",word); } @Test public void testCheckAnswer(){ //StubDBconnect data = new StubDBconnect(); assertTrue(test.checkAnswer("Hello", "привет", data)); } @Test public void testCheckIncorrectAnswer(){ //StubDBconnect data = new StubDBconnect(); assertFalse(test.checkAnswer("Hello", "пока", data)); } @Test public void testGenerateAnswerForImproperWord(){ //StubDBconnect data = new StubDBconnect(); String result = test.generateAnswerForImproperWord("Hello", "пока", 1, data); String standard = "Неправильный ответ на вопрос № 1\n"+ "Слово Hello\n"+ "Ваш ответ пока\n"+ "Правильный ответ [привет]"; assertEquals(standard,result); } }
При проверке кода EnglishTestingTest.txt в IDE Netbeans 6.5 Вы получите следующий результат:
Для того, чтобы проверить покрытие Unit-тестами исходного кода необходимо использовать какой-нибудь plugin. К примеру, в Netbeans можно установить plugin EMMA (Code Coverage Plugin). Для этого нужно проделать следующие действия:
Если есть необходимость запускать сразу несколько файлов с тестами одновременно , то можно воспользоваться Test Suite эту возможность также предоставляет JUnit 4.
Для этого Вам нужно создать новый класс, к примеру, SuiteTests, как показано ниже:
//:suite/SuiteTests.java
package suite;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
/**
* JUnit - suite class
* @author Shpatserman Maria
*/
@RunWith(value=Suite.class)
@SuiteClasses(value = {
testing.EnglishTestingTest.class
})
public class SuiteTests {
}
Suite - это контейнер из нескольких тестов. Для того, чтобы обозначить класс как Suite нужно использовать обозначение @RunWith(value=Suite.class), а также в блоке @SuiteClasses указать те тестовые классы, которые должны запускаться.
В исходниках я также выложила perl скрипт insert.pl для распарсивания words.csv с добавлением новых слов в БД.