2015-12-30 2 views
4

В настоящее время я пишу много тестов JUnit для устаревшей системы.Лучшая практика Junit при утверждении сложных объектов

Часто я перехожу к вопросу: Каков наилучший способ утверждения сложных объектов?

Вот мой текущего код

public class SomeParserTest { 

    @Test 
    public void testParse() throws Exception { 
     final SomeParser someParser = new SomeParser(); 
     someParser.parse("string from some file"); 

     final List<Result> listOfResults = someParser.getResults(); 
     assertThat(listOfResults, hasSize(5)); 

     assertResult(listOfResults.get(0), "20151223", 2411189L, isEmptyOrNullString(), "2.71", "16.99"); 
     assertResult(listOfResults.get(1), "20151229", 2411190L, isEmptyOrNullString(), "2.86", "17.9"); 
     assertResult(listOfResults.get(2), "20151229", 2411191L, is("1.26"), ".75", "23.95"); 
     assertResult(listOfResults.get(3), "20151229", 2411192L, is("2.52"), "1.5", "47.9"); 
     assertResult(listOfResults.get(4), "20151229", 2411193L, isEmptyOrNullString(), "2.71", "16.99"); 

     final List<SubResult> listofSubResuls = someParser.getSubResultOf(listOfResults.get(0)); 
     assertThat(listofSubResuls, hasSize(1)); 
     assertSubResult(listofSubResuls.get(0), 12.5D, "20151223", 1L, 14.87D, 16.99D, 0L, null, 67152L, "20151223", "2", 0L, "02411189", 56744349L); 

     final List<SubResult> listofSubResuls1 = someParser.getListofBBBS(listOfResults.get(1)); 
     assertThat(listofSubResuls1, hasSize(2)); 
     assertSubResult(listofSubResuls1.get(0), 30.0D, "20151228", 1L, 12.53D, 17.9D, 0L, null, 67156L, "20151229", "2", 0L, "02411190", 56777888L); 
     assertSubResult(listofSubResuls1.get(1), 33.3D, "20151228", 1L, 4.66D, 6.99D, 1L, "J", 67156L, "20151229", "2", 21L, "02411190", 56777889L); 
//And 50 Lines more 
    } 

// how to avoid so many parameters? 
    private void assertSubResult(final SubResult subResult, final double someDouble, final String bestellDatum, 
      final long someLong, final double someDouble2, final double someDouble3, final long someLong3, 
      final String someString, 
      final long someLong1, 
      final String someString4, final String someString3, final long someLong4, final String rechnungsNummer, 
      final long someLong2) { 
     assertThat(subResult.getXXX(), is(nullValue())); 
     assertThat(subResult.getXYX().getTag(), is(someDouble2)); 
     assertThat(subResult.getXYX(), is("some constant")); 
//  and much more 
    } 

    // how to avoid so many parameters? 
    private void assertResult(final Result result, final String string1234, final long abc, 
      final String string1, final String string12, final String string134) { 
     assertThat(result.getXXX(), is(nullValue())); 
     assertThat(result.getXYX().getTag(), is(someDouble2)); 
     assertThat(result.getXYX(), is("some constant")); 
//  and much more 
    } 
} 

Там нет простого способа проверить каждый шаг такого синтаксического анализа, и я не могу cahnge, что много, так как это унаследованный код ...

Спасибо за вашу помощь!

+1

Что я делаю для упрощения этого кода, это проверить значение toString(). Это делает относительно хрупким (что может быть или не желательно), но легко поддерживать тесты. Для списка я перехожу toString() в многострочный вывод, поэтому среда IDE может вызвать окно сравнения, чтобы легко увидеть различия. –

+1

Это может работать во многих случаях, но не в моем. Тест не будет охватывать логику в геттерах (да, это плохая практика, но ее устаревший код.) Также есть метод '' toString'', который не охватывает все поля, yay ... – Zarathustra

ответ

0

Вместо длинной подписи метода я бы сделал что-то вроде. (Псевдо-код, отказ от ответственности в случае, если он не компилируется):

class AssertResult { 
    private int xxx; 
    private String yyy; 
    public AssertResult setXXX(int xxx) { 
     this.xxx = xxx; 
     return this; 
    } 
    public AssertResult setYYY(String yyy) { 
     this.yyy = yyy; 
     return this; 
    } 
    public void check(Result result) { 
     assertThat(result.getXXX(), is(xxx)); 
     assertThat(result.getYYY(), is(yyy)); 
    } 
} 

и тогда я мог бы использовать его как это:

new AssertResult().setXXX(123).setYYY("asdasd").check(result); 
+0

Тогда мне пришлось бы напишите '' AssertResult.start (listOfResults.get (0)). assertXXX (123) .assertYYY ("asdasd"); '' вместо '' assertThat (subResult.getXXX(), является («что-то»); '' И я мог пропустить некоторые утверждения, когда все они в одном месте (этот длинный метод) заставляют меня делать asserion. – Zarathustra

+0

изменил ответ, чтобы сделать утверждения в конце. Он был основан на шаблоне построителя: https: // en .wikipedia.org/вики/Builder_pattern –

-1

Вы можете взглянуть на hamcrest Matchers в сочетании с assertThat() способ из юнит. Вы можете найти свой тестовый код выглядит немного больше как

assertThat(listOfResults.get(0), equalTo(expectedObject)); 

В качестве альтернативы, есть assertj, который позволяет писать вспомогательные классы, которые цепные несколько отдельных утверждений о том же объекте в беглой манере, используя версию assertJ из assertThat довольно чем JUnit's. Это позволит ваш тестовый код, чтобы выглядеть немного больше как

assertThat(listOfResults.get(0)).hasXXX("someString").hasYYY(1.234) 
3

Как Сизиф я предложил бы использовать Hamcrest matchers.

Но я рекомендую запрограммировать custom matcher.После линии

assertResult(listOfResults.get(0), "20151223", 2411189L, isEmptyOrNullString(), "2.71", "16.99"); 

может выглядеть так:

assertThat(listOfResults, contains(
    ResultMatcher.matchesResult().withFirstAttribute("20151223").andSecondAttribute(2411189L)... 
    ... // here the matchers for the other elements of the list 
)); 

Вам понадобится специальный класс Сличитель ResultMatcher который должен иметь следующий вид:

class ResultMatcher extends TypeSafeMatcher<Result> { 
    Matcher<String> firstAttribute = Matchers.any(String.class); 
    Matcher<String> secondAttribute = Matchers.any(String.class); 
    ... 

    ResultMatcher withFirstAttribute(String firstAttribute) { 
    this.firstAttribute = Matchers.equalTo(firstAttribute); 
    return this; 
    } 

    ... 

    public boolean matchesSafely(Result result) { 
    if (!firstAttribute.matches(result.getFirstAttribute())) { 
     return false 
    } 
    ... 
    return true; 
    } 

} 

Есть некоторые преимущества в этой конструкции:

  • вам не нужен метод equals-метода, который должен быть определен
  • вы можете определить значения по умолчанию для каждого атрибута, чтобы вы могли тестировать только те атрибуты, которые вас интересуют, и сопоставлять другие по умолчанию.
  • тест не должен проверять каждый атрибут объект (сличитель это делает)
2

Я хотел бы дать assertj извлекая функцию попробовать, например:

// fellowshipOfTheRing is a List<TolkienCharacter> 
assertThat(fellowshipOfTheRing).extracting("name", "age", "race.name") 
           .contains(tuple("Boromir", 37, "Man"), 
             tuple("Sam", 38, "Hobbit"), 
             tuple("Legolas", 1000, "Elf")); 

пример подробно описан здесь: http://joel-costigliola.github.io/assertj/assertj-core-features-highlight.html#extracted-properties-assertion

Вы также можете использовать определенную сравнительную стратегию для сравнения фактических и ожидаемых результатов, и, наконец, поддержка поля полевым сопоставлением: isEqualToComparingFieldByField, isEqualToComparingOnlyGivenFields и isEqualToIgnoringGivenFields.

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

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