Возможно ли в Qt юнит-тестирование (доступ) закрытых методов? - PullRequest
3 голосов
/ 13 сентября 2011

Я пишу модульные тесты для своего приложения, и теперь я наткнулся на класс, в котором я должен тестировать частные методы.Это может быть результатом плохого дизайна определенного класса, но я должен это сделать.Есть ли способ в Qt вызывать закрытые методы, возможно, используя QMetaObject или что-то подобное?

Для модульного тестирования я использую фреймворк QTestLib.

Ответы [ 5 ]

5 голосов
/ 13 сентября 2011

Правильный (читай раздражающий) ответ: вам не следует тестировать приватные методы, это детали реализации ;-).

OTOH - задумывались ли вы об условном объявлении их защищенными / приватными в зависимости от того,ты в тестировании или нет а потом расширяешься?Я использовал это, чтобы вытащить меня из подобной ситуации в прошлом.

#ifdef TESTING
// or maybe even public!
#define ACCESS protected
#else
#define ACCESS private
#endif

/* your class here */
class Foo {
ACCESS
    int fooeyness;
}

// or better yet, place this in a different file!
#ifdef TESTING
/*
    class which extends the tested class which has public accessors
*/
#endif
2 голосов
/ 04 апреля 2014

Решение 1, быстрое и простое: сделайте тестовый класс (ы) другом общедоступного.

class Foo {
   // ...
private:
   friend class FooTest;
};

Таким образом, ваш FooTest класс может получить доступ ко всем членам открытого класса. Однако таким образом вам нужно изменять исходный класс каждый раз, когда вы хотите получить доступ к частным данным из другого теста, и вы пропускаете информацию о тестах в общедоступном API, и вы, возможно, открыты для конфликтов имен классов (что, если есть / другой класс FooTest?) и т. д.


Решение 2, иначе правильно сделано: не помещайте приватные методы в открытый класс, но создавайте приватный класс с открытыми методами.

class Foo {
    // 
private:
    friend class FooPrivate;
    FooPrivate *d;
};

FooPrivate объявляется в своем собственном заголовке, который может быть не установлен, или находиться в подкаталоге include-privates /, или где-либо еще, т. Е. Он не используется для обычного использования. Общественный класс остается чистым таким образом.

class FooPrivate {
public:
    // only public stuff in here;
    // and especially this:
    static FooPrivate *get(Foo *f) { return f->d; }
};

Затем тест включает закрытый заголовок и вызывает FooPrivate::get(fooObj), чтобы получить экземпляр закрытого класса, а затем успешно использует его.

1 голос
/ 17 июля 2016

Я не согласен с менталитетом «частные члены - детали реализации», в моем представлении это примерно переводится как «тестировать только часть вашего кода».

Я могу относиться к аргументу «единицы - единицы», нопочему бы не попытаться покрыть как можно большую часть кода тестами, даже внутри модулей?Ака. предоставление вашим подразделениям тщательного ректального обследования .

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

  1. Всегда объявляйте членов, которые вы хотите проверить, как protected вместо private в вашем коде.
  2. Подкласс своего класса в тестовом коде и просто сделайте нужные селекторы или простонаписать тест-код непосредственно в качестве членов в реализации этого подкласса.

ПРИМЕЧАНИЕ: вы должны быть осторожны с классами, которые полагаются на сложные шаблоны создания экземпляров, чтобы убедиться, что вы их правильно конструируете (читай: callконструктор исходного класса из ctor подкласса).

0 голосов
/ 04 апреля 2014

Я однажды читал, что модульный тест должен проверять открытый интерфейс класса, а не защищенный / приватный материал.

Ваш класс должен вести себя прямо снаружи. Если стратегия реализации изменится, ваш класс модульного теста останется прежним.

0 голосов
/ 13 сентября 2011

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

Foo a;

Тогда мы можем использовать QMetaObject :: invokeMethod для вызова любого слота, который есть у метода (публичный или приватный). Поэтому, если мы хотим вызвать метод Test, мы можем сделать это так:

QMetaObject::invokeMethod(&a, "Test", Qt::DirectConnection);

Кроме того, мы можем получить возвращаемое значение и отправить аргументы ... На самом деле, здесь все ответили: http://doc.qt.nokia.com/stable/qmetaobject.html#invokeMethod

...