Поблочное тестирование класс без возвращаемого значения?

Я сделал это только что. Это соответствует каждому компоненту названия CamelCase.

/([A-Z]+(?=$|[A-Z][a-z])|[A-Z]?[a-z]+)/g

, Например:

"SimpleHTTPServer" => ["Simple", "HTTP", "Server"]
"camelCase" => ["camel", "Case"]

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

Regex.Replace(s, "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))", "$1 ")
<час>

, Если необходимо обработать цифры:

/([A-Z]+(?=$|[A-Z][a-z]|[0-9])|[A-Z]?[a-z]+|[0-9]+)/g

Regex.Replace(s,"([a-z](?=[A-Z]|[0-9])|[A-Z](?=[A-Z][a-z]|[0-9])|[0-9](?=[^0-9]))","$1 ")
23
задан Community 23 May 2017 в 11:55
поделиться

7 ответов

What you ' Повторное описание часто называют проверкой поведения (в отличие от проверки состояния). У него есть сторонники и противники, но для нескольких категорий классов это единственная игра в городе, если вы хотите провести модульное тестирование.

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

Если бы вы делали это вручную (фу!) для классов, упомянутых в вашем вопросе, вы могли бы создать Класс MockParser , который реализует IParser и добавляет свойства, которые фиксируют, были ли и как были вызваны его методы.

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

Я использую NMock2 в эти дни, и тесты выглядят примерно так:

// 'mockery' is the central framework object and Mock object factory
IParser mockParser   = mockery.NewMock<IParser>();

// Other dependencies omitted
Job     job          = new Job(mockParser);

// This just ensures this method is called so the return value doesn't matter
Expect.Once.On(mockParser).
    .Method("Parse").
    .WithAnyArguments().
    .Will(Return.Value(new object()));

job.Run();
mockery.VerifyAllExpectationsHaveBeenMet();
18
ответ дан 29 November 2019 в 02:34
поделиться

Когда вы вводите макет, вы передаете конструктору класса Run тестовый класс, который спрашивает, прошел ли тест. Например, вы можете проверить, что макет IParser получил правильный запрос, учитывая файл Excel, который вы передали в конструктор. Вы можете сделать это через свой собственный класс, собрать в нем результаты и протестировать то, что он собрал, или вы можете сделать это через фреймворк имитирования, который дает вам способы выразить такое тестирование без создания класса.

Я вижу, что вы пометил ваш вопрос с помощью tdd, но в истинном tdd вы действительно не получите этот вопрос (вы задаете, но задаете по-другому), потому что вы сначала создаете тест, который определяет интерфейс, вместо того, чтобы создавать интерфейс класса, а затем думать, как вы собираюсь протестировать эту вещь. Необходимость опробовать дизайн дисков.

5
ответ дан 29 November 2019 в 02:34
поделиться

Вы упомянули, что у вас есть фиктивные реализации 3 классов / интерфейсов, используемых в вашем автономном классе ...

Почему бы не создать некоторые известные значения для возврата из вашего фиктивного IConnection, просто пропустите все их через свой фиктивный IParser и сохраните их в своем фиктивном IDataAccess - затем в тестовой проверке, чтобы увидеть, что результаты в фиктивном IDataAccess соответствуют ожидаемым результатам из входных данных из фиктивного IConnection после выполнения run () метод?

Отредактировано, чтобы добавить пример -

Интерфейсы / классы приложений:

public interface IConnection {
    public List<Foo> findFoos();
}

public interface IParser {
    public List<Foo> parse(List<Foo> originalFoos);
}

public interface IDataAccess {
    public void save(List<Foo> toSave);
}

public class Job implements Runnable {
    private IConnection connection;
    private IParser parser;
    private IDataAccess dataAccess;

    public Job(IConnection connection, IParser parser, IDataAccess dataAccess) {
        this.connection = connection;
        this.parser = parser;
        this.dataAccess = dataAccess;
    }

    public void run() {
        List<Foo> allFoos = connection.findFoos();
        List<Foo> someFoos = parser.parse(allFoos);
        dataAccess.save(someFoos);
    }
}

Моки / тестовые классы:

public class MockConnection implements IConnection {
    private List<Foo> foos;

    public List<Foo> findFoos() {
        return foos;
    }

    public void setFoos(List<Foo> foos) {
        this.foos = foos;
    }
}

public class MockParser implements IParser {

    private int[] keepIndexes = new int[0];

    public List<Foo> parse(List<Foo> originalFoos) {
        List<Foo> parsedFoos = new ArrayList<Foo>();
        for (int i = 0; i < originalFoos.size(); i++) {
            for (int j = 0; j < keepIndexes.length; j++) {
                if (i == keepIndexes[j]) {
                    parsedFoos.add(originalFoos.get(i));
                }
            }
        }
        return parsedFoos;
    }

    public void setKeepIndexes(int[] keepIndexes) {
        this.keepIndexes = keepIndexes;
    }
}

public class MockDataAccess implements IDataAccess {
    private List<Foo> saved;

    public void save(List<Foo> toSave) {
        saved = toSave;
    }

    public List<Foo> getSaved() {
        return saved;
    }
}

public class JobTestCase extends TestCase {

    public void testJob() {
        List<Foo> foos = new ArrayList<Foo>();
        foos.add(new Foo(0));
        foos.add(new Foo(1));
        foos.add(new Foo(2));
        MockConnection connection = new MockConnection();
        connection.setFoos(foos);
        int[] keepIndexes = new int[] {1, 2};
        MockParser parser = new MockParser();
        parser.setKeepIndexes(keepIndexes);
        MockDataAccess dataAccess = new MockDataAccess();
        Job job = new Job(connection, parser, dataAccess);
        job.run();
        List<Foo> savedFoos = dataAccess.getSaved();
        assertTrue(savedFoos.length == 2);
        assertTrue(savedFoos.contains(foos.get(1)));
        assertTrue(savedFoos.contains(foos.get(2)));
        assertFalse(savedFoos.contains(foos.get(0)));
    }
}
3
ответ дан 29 November 2019 в 02:34
поделиться

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

Я понял, что вы можете изменить реализацию Job.Run, и в этом случае, если вы хотите, чтобы код можно было тестировать, вы должны что-то с ним сделать, чтобы иметь возможность чтобы прочитать значения, которые необходимо проверить.

2
ответ дан 29 November 2019 в 02:34
поделиться

Если единственное, что делает ваш метод run () , - это вызов других объектов, то вы проверяете его, но проверяете, были ли вызваны имитаторы. То, как именно вы это сделаете, зависит от макета пакета, но обычно вы найдете какой-то метод "expect".

Не пишите в своем методе run () код, который будет отслеживать его выполнение. Если вы не можете проверить работу метода на основе его взаимодействий с соавторами (макеты), это указывает на необходимость переосмыслить эти взаимодействия. Это также загромождает основной код, увеличивая затраты на обслуживание.

1
ответ дан 29 November 2019 в 02:34
поделиться

I've asked a similar question.

Though (sense over theory) I do think that some methods don't need unit tests as long as (and until) they:

  • don't return any values
  • don't change internal state of the class or system that can be checked
  • don't rely on anything else (as input or output) than your mock

If their functionality (ie. sequence of calls) is vital you will have to verify that internal functionality is met though. Meaning that you have to verify (using your mocks) that those methods have been called with correct parameters and correct sequence (if it matters).

1
ответ дан 29 November 2019 в 02:34
поделиться

Измените свой список на ObservableCollection . Он реализует INotifyCollectionChanged , поэтому вы можете подписаться на его события изменения.

Другой вариант - использовать BindingList , если вам нужна семантика полного списка.

отправляет запрос стороннему поставщику данных, берет результат и помещает его в базу данных и регистрирует начало / конец задания

Итак, у вас есть:

  • некоторые входные данные (из файла Excel)

  • какие-то "выходные" данные, а точнее результат работы потока.

Для успешного выполнения run () необходимо убедиться, что:

a) запрос был отправлен третьей стороне и / или получен результат. Я не знаю, какой из них будет легче проверить, но, по крайней мере, вы могли бы, по крайней мере, зарегистрировать запрос / ответ и проверить журналы (в модульном тесте) на предмет выполняемой операции. Это обеспечит выполнение всего рабочего процесса (мы можем представить себе сценарий, в котором правильные данные присутствуют в базе данных в конце рабочего процесса, но не потому, что запуск работал правильно,

1
ответ дан 29 November 2019 в 02:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: