2016-09-09 4 views
0

Хотя я не совсем новичка в тестирование и модульное тестирование, в частности, я часто смущаюсь в отношении к вещам, как в следующие:Должны ли проходить чередующие тесты?

Представьте себе следующую реализацию я хочу, чтобы проверить (да, я знаю TDD FTW;))

private Value0Service value0Service = new Value0Service(); 
private Value1Service value1Service = new Value1Service(); 

public SomeInfo readInfo(final Long id, final Value value0, final Value value1) { 
    final Value1 actualValue0 = fetchValue0IfNullElseReturnGiven(id, value0); 
    final Value2 actualValue1 = fetchValue1IfNullElseReturnGiven(value1); 

    return SomeInfo(actualValue0, actualValue1); 
} 

private Value fetchValue0IfNullElseReturnGiven(Long id, Value value0) { 
    if(value0== null) { 
     return value0Service.getById(id); 
    } 
    return value0; 
} 

private Value fetchValue1IfNullElseReturnGiven(Value value0, Value value1) { 
    if(value1 == null) { 
     return value1Service.getByValue0(value0); 
    } 
    return value1; 
} 

Хотя это построенный пример, я надеюсь, что цель понятна.

Теперь, если я пишу тесты, достаточно ли этого, чтобы покрыть поведение для каждого метода «выборки», или мне также нужно пройти мои тесты? Что я имею в виду, что:

ли я только утверждаю, что мое возвращение значение readInfoSomeInfo установил соответствующий параметр или я всегда проверить оба?

(Я извиняюсь, это трудно объяснить на английском языке), я должен чередовать мои тесты как:

// ValueServices are to be treated as mocks from here, so imagine Value0Service value0ServiceMock = mock(Value0Service.class) in the tests! 

@Test 
public void ifBothValuesAreGivenThenSomeInfoIsFilledWithGivenForBoth() { 
    Value value0 = new Value(); 
    Value value1 = new Value(); 

    SomeInfo info = myTestObject.readInfo(VALID_ID, value0, value1); 
    assertThat(info.getValue0()).isEqualTo(value0); 
    assertThat(info.getValue1()).isEqualTo(value1); 
} 

@Test 
public void ifValue0IsNullAndValue1IsNotThenSomeInfoIsFilledWithFetchedForValue0AndGivenForValue1() { 
    Value value1 = new Value(); 

    Value fetchedValue0 = new Value(); 
    doReturn(fetchedValue0).when(value0ServiceMock).getById(VALID_ID); 

    SomeInfo info = myTestObject.readInfo(VALID_ID, null, value1); 
    assertThat(info.getValue0()).isEqualTo(fetchedValue0); 
    assertThat(info.getValue1()).isEqualTo(value1); 
} 

@Test 
public void ifValue0IsNotNullAndValue1IsThenSomeInfoIsFilledWithGivenForValue0AndFetchedForValue1() { 
    Value value0 = new Value(); 

    Value fetchedValue1 = new Value(); 
    doReturn(fetchedValue1).when(value1ServiceMock).getByValue(value0); 

    SomeInfo info = myTestObject.readInfo(VALID_ID, value0, null); 
    assertThat(info.getValue0()).isEqualTo(value0); 
    assertThat(info.getValue1()).isEqualTo(fetchedValue1); 
} 

@Test 
public void ifValue0IsNullAndValue1IsNullThenSomeInfoIsFilledWithFetchedForBoth() { 
    Value fetchedValue0 = new Value(); 
    Value fetchedValue1 = new Value(); 
    doReturn(fetchedValue0).when(value0ServiceMock).getById(VALID_ID); 
    doReturn(fetchedValue1).when(value1ServiceMock).getByValue(fetchedValue0); 

    SomeInfo info = myTestObject.readInfo(VALID_ID, null, null); 

    assertThat(info.getValue0()).isEqualTo(fetchedValue0); 
    assertThat(info.getValue1()).isEqualTo(fetchedValue1); 
} 

Должен ли я всегда добавляю утверждает для обоих значений, или только один? В обоих случаях я бы написал 4 теста, поэтому мне интересно, потому что мне сказали, что хороший способ справиться с утверждениями - это просто один за тест, иначе вы делаете что-то неправильно.

ответ

1

В этом конкретном примере вы должны реализовать метод equals для SomeInfo. Это позволит вам иметь только одно утверждения:

SomeInfo expectedInfo = new SomeInfo(...); 

assertThat(myTestObject.readInfo(VALID_ID, null, null)).isEqualTo(expectedInfo); 

Однако, ваш вопрос до сих пор стоит и что-то я наталкиваюсь все время. Имея только одно утверждение за тест, важно для того, чтобы убедиться, что тесты читаемы будущим программистом. Хитрость заключается в том, чтобы решить, что считается «одним утверждением». Давайте посмотрим на ваш пример:

assertThat(info.getValue0()).isEqualTo(fetchedValue0); 
assertThat(info.getValue1()).isEqualTo(fetchedValue1); 

Вы можете возразить, что, хотя есть два вызова метода assertThat, это действительно только одно логическое утверждение - мы проверяем значение info правильно. Проблемы случаются, когда у вас есть два утверждения, как это:

@Test 
public void multipleAssertions() { 
    Value value1 = serviceUnderTest.getValue(...); 
    assertThat(value1).isEqualTo(expectedValue1); 

    Value value2 = serviceUnderTest.getValue(...); 
    assertThat(value2).isEqualTo(expectedValue2); 
} 

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

Последний вопрос: вы получаете эту проблему только при написании тестов после код был уже написан. Как вы говорите, «TDD ftw!». Если тесты сначала записываются, следуя минимально возможному количеству кода для прохождения теста, у вас никогда не возникает этой проблемы, потому что вы просто прекращаете запись теста после первого утверждения и переходите к следующему тесту.

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