Подтвердить что ты не робот

Как конструкторы unit test

У меня есть класс, к которому я добавляю модульные тесты. Класс имеет несколько конструкторов, которые принимают разные типы и преобразуют их в каноническую форму, которые затем могут быть преобразованы в другие типы.

public class Money {
    public Money(long l) {
        this.value = l;
    }

    public Money(String s) {
        this.value = toLong(s);
    }

    public long getLong() {
        return this.value;
    }

    public String getString() {
        return toString(this.value);
    }
}

В действительности есть несколько других типов, которые он принимает и преобразует в.

Я пытаюсь выяснить, какой наиболее подходящий способ проверить эти конструкторы.

Должен ли быть тестовый конструктор и тип вывода:

@Test
public void longConstructor_getLong_MatchesValuePassedToConstructor() {
    final long value = 1.00l;

    Money m = new Money(value);
    long result = m.getLong();

    assertEquals(value, result);
}

Это приводит к множеству различных тестов. Как вы можете видеть, я изо всех сил пытаюсь назвать их.

Если существует несколько утверждений:

@Test
public void longConstructor_outputsMatchValuePassedToConstructor() {
    final long longValue = 1.00l;
    final String stringResult = "1.00";

    Money m = new Money(longValue);

    assertEquals(longValue, m.getLong());
    assertEquals(stringResult, m.getString());
}

У этого есть несколько утверждений, что делает меня неудобным. Он также тестирует getString (и по прокси toString), но не указывает, что в имени теста. Назвать их еще сложнее.

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

@Test
public void getString_MatchesValuePassedToConstructor() {
    final long value = 1.00;
    final String expectedResult = "1.00";

    Money m = new Money(value);
    String result = m.getLong();
    assertEquals(expectedResult, result);
}

Это унаследованный класс, и я не могу изменить исходный класс.

4b9b3361

Ответ 1

Похоже, у вас есть канонический способ получения "необработанного" значения (toLong в этом случае) - так что просто проверьте, что все конструкторы верны, когда вы извлекаете это значение. Затем вы можете протестировать другие методы (например, getString()) на основе одного конструктора, так как вы знаете, что после завершения всех конструкторов все они оставляют объект в том же состоянии.

Это предполагает несколько белых тестов - т.е. вы знаете, что toLong на самом деле является простым отражением внутреннего состояния, поэтому хорошо проверить это + конструктор в тесте.

Ответ 2

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

@Test
public void moneyConstructorThatTakesALong {

Ответ 3

Ожидаемый результат теста конструктора: экземпляр создан

Следуя этой идее, вы можете ограничить работу в конструкторских тестах чистому экземпляром:

@Test public void testMoneyString() {
    try {
      new Money("0");
      new Money("10.0");
      new Money("-10.0");
    } catch (Exception e) {
      fail(e.getMessage());
    }
}

@Test public void testMoneyStringIllegalValue() {
    try {
      new Money(null);
      fail("Exception was expected for null input");
    } catch (IllegalArgumentException e) {          
    }

    try {
      new Money("");
      fail("Exception was expected for empty input");
    } catch (IllegalArgumentException e) {          
    }

    try {
      new Money("abc");
      fail("Exception was expected for non-number input");
    } catch (IllegalArgumentException e) {          
    }

}

Тест, чтобы проверить, могут ли преобразования работать с геттерами.

Ответ 4

Это не идея BAD для тестирования конструкторов, чтобы удостовериться, что взять данные по мере необходимости, но если вам действительно не нравятся несколько утверждений, разделите их и назовите метод с тем, что они делают пример: CanContructorAcceptString или: CanConstructorAcceptNonLongStringValue

Что-то вроде этого.

Ответ 5

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

Лично в таком простом случае я бы пошел с единственным тестовым примером, который проверяет конструкторы. Это устраняет необходимость в чрезмерных и довольно громоздких именах методов.

Ответ 6

У вас есть несколько входов (через конструкторы) и несколько выходов (с помощью разных методов getX()). Но количество членов, которых он внутренне, кажется, меньше (в вашем примере - 1 длинное значение). Не было бы легче сначала протестировать разные входы, создав x разных объектов, используя x разных конструкторов. Затем вы можете проверить, все ли они равны, используя реализованный метод equals(). Это можно сделать одним методом тестирования.

Затем вы можете проверять возможные методы getter один за другим, не используя все разные конструкторы.

Конечно, это требует, чтобы вы выполняли (отдельно тест) метод equals.

В вашем примере я бы создал следующие тестовые файлы:

@Test
public void testEquals() {
    Money m1 = new Money(1);
    Money m2 = new Money(1);
    Money m3 = new Money(2);

    assertEquals(m1, m2);
    assertEquals(m2, m1);
    assertNotEquals(m1, m3);
    assertNotEquals(m3, m1);
    assertNotEquals(m1, null);
}

private void testConstructors(long lValue, String sValue) {
    Money m1 = new Money(lValue);
    Money m2 = new Money(sValue);

    assertEquals(m1, m2);
}

@Test
public void testConstructorsPositive() {
    testConstructors(1, "1");
}

@Test
public void testConstructorsNegative() {
    testConstructors(-1, "-1");
}

@Test
public void testConstructorsZero() {
    testConstructors(0, "0");
}

@Test
public void testGet...() { /* etc... */ }