Как тестировать абстрактные классы: дополнить заглушками? - PullRequest
414 голосов
/ 28 октября 2008

Мне было интересно, как проводить модульное тестирование абстрактных классов и классов, расширяющих абстрактные классы.

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

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

Обратите внимание, что в моем абстрактном классе есть несколько конкретных методов.

Ответы [ 14 ]

2 голосов
/ 28 октября 2008

Одним из основных мотивов использования абстрактного класса является включение полиморфизма в вашем приложении, т. Е. Вы можете заменить другую версию во время выполнения. Фактически, это почти то же самое, что и использование интерфейса, за исключением того, что абстрактный класс обеспечивает некоторые общие условия, часто называемые Шаблон шаблона .

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

  1. Взаимодействие вашего абстрактного класса с соответствующими классами . Использование фиктивной среды тестирования идеально подходит для этого сценария, поскольку оно показывает, что ваш абстрактный класс хорошо сочетается с другими.

  2. Функциональность производных классов . Если у вас есть пользовательская логика, которую вы написали для своих производных классов, вам следует тестировать эти классы изолированно.

edit: RhinoMocks - это потрясающая среда для фиктивного тестирования, которая может генерировать фиктивные объекты во время выполнения, динамически наследуя ваш класс. Этот подход может сэкономить вам бесчисленные часы ручного кодирования производных классов.

2 голосов
/ 28 октября 2008

Полагаю, вы могли бы захотеть протестировать базовую функциональность абстрактного класса ... Но вам, вероятно, лучше всего расширить класс, не переопределяя какие-либо методы, и сделать минимум усилий для абстрактных методов.

1 голос
/ 23 января 2017

После ответа @ patrick-desjardins я реализовал абстрактный и его класс реализации вместе с @Test следующим образом:

Абстрактный класс - ABC.java

import java.util.ArrayList;
import java.util.List;

public abstract class ABC {

    abstract String sayHello();

    public List<String> getList() {
        final List<String> defaultList = new ArrayList<>();
        defaultList.add("abstract class");
        return defaultList;
    }
}

Как Абстрактные классы не могут быть созданы, но они могут быть разделены на подклассы , конкретный класс DEF.java , выглядит следующим образом:

public class DEF extends ABC {

    @Override
    public String sayHello() {
        return "Hello!";
    }
}

@ Test класс для проверки как абстрактного, так и неабстрактного метода:

import org.junit.Before;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.contains;
import java.util.Collection;
import java.util.List;
import static org.hamcrest.Matchers.equalTo;

import org.junit.Test;

public class DEFTest {

    private DEF def;

    @Before
    public void setup() {
        def = new DEF();
    }

    @Test
    public void add(){
        String result = def.sayHello();
        assertThat(result, is(equalTo("Hello!")));
    }

    @Test
    public void getList(){
        List<String> result = def.getList();
        assertThat((Collection<String>) result, is(not(empty())));
        assertThat(result, contains("abstract class"));
    }
}
0 голосов
/ 24 января 2018

Если абстрактный класс подходит для вашей реализации, протестируйте (как предложено выше) производный конкретный класс. Ваши предположения верны.

Чтобы избежать путаницы в будущем, имейте в виду, что этот конкретный тестовый класс - не фиктивный, а фальшивый .

В строгом смысле, макет определяется следующими характеристиками:

  • Вместо каждой и каждой зависимости тестируемого предметного класса используется макет.
  • Макет - это псевдо-реализация интерфейса (вы можете вспомнить, что, как правило, зависимости должны быть объявлены как интерфейсы; тестируемость является одной из основных причин этого)
  • Поведение членов интерфейса макета - методы или свойства - предоставляются во время тестирования (опять же, с использованием насмешливой основы). Таким образом, вы избегаете связи тестируемой реализации с реализацией ее зависимостей (которые должны иметь свои собственные дискретные тесты).
...