Задачи модульного тестирования выполняются параллельно с использованием QThreadPool - PullRequest
0 голосов
/ 25 марта 2019

Я использую QThreadPool для параллельного запуска задач в моем приложении. Задачи принимают в качестве аргумента пул потоков, чтобы они могли запускать новые задачи. Как я могу написать модульные тесты для задач и утверждать, что правильные следующие задачи запущены?

class MyTask: public QRunnable {
public:
    virtual void run() {
        m_threadPool.start(/*another task*/);
        m_threadPool.start(/*a third task*/);
    }
private:
    QThreadPool &m_threadPool;
};

Я бы хотел проверить MyTask:

QThreadPool threadPool;
threadPool.start(new MyTask(threadPool));
threadPool.waitForDone();

// Assert that another task and a third task is started.

Я попытался расширить QThreadPool и запустить журнал задач:

class MyThreadPool : public QThreadPool {
public:
    virtual void start(QRunnable *runnable, int priority = 0) {
        m_Queue.enqueue(runnable);
        // The task is not started, so I can manually start each task and test the outcome.
    }
    QQueue<QRunnable *> queue() const { return m_queue; }
private:
    QQueue<QRunnable *> m_queue;
};


MyThreadPool threadPool;
threadPool.start(new MyTask(threadPool));
threadPool.waitForDone();

QQueue<QRunnable *> Queue({ /*another task and a third task*/ });
Assert::IsEquavalent(threadPool.queue(), Queue);

Но это не работает, поскольку QThreadPool::start() не является виртуальным. Каков наилучший подход к написанию моего теста?

1 Ответ

0 голосов
/ 25 марта 2019

Что касается проблем с тем, что QThreadPool::start() не является виртуальной функцией, вы можете сделать что-то вроде этого:

Вместо переопределения функции вы можете использовать свой подкласс в MyTask и использовать другую функцию, которая вызовет run. Примерно так:

class MyThreadPool : public QThreadPool {
public:
    void enqueue_and_run(QRunnable *runnable, int priority = 0) {
        m_Queue.enqueue(runnable);
        QThreadPool::start(runnable, priority);
    }

    const QQueue<QRunnable *>& queue() const { 
         return m_queue; 
    }
private:
    QQueue<QRunnable *> m_queue;
};

class MyTask: public QRunnable {
public:
    virtual void run() {
        m_threadPool.enqueue_and_run(/*another task*/);
        m_threadPool.enqueue_and_run(/*a third task*/);
    }
private:
    MyThreadPool &m_threadPool;
};

Затем запустите тот же тестовый код:

MyThreadPool threadPool;
threadPool.enqueue_and_run(new MyTask(threadPool));
threadPool.waitForDone();

QQueue<QRunnable *> Queue({ /*another task and a third task*/ });
Assert::IsEquavalent(threadPool.queue(), Queue);

Это не самый элегантный способ сделать это, но он проясняет ваши намерения.

В качестве альтернативы, если вы хотите сохранить общий интерфейс, вы можете использовать базовую функцию перегрузки:

template <class TPool>
void start(TPool* pool, QRunnable *runnable, int priority = 0) {
    pool->start(runnable, priority);
}

void start(MyThreadPool* pool, QRunnable *runnable, int priority = 0) {
    pool->enqueue_and_run(pool, runnable, priority);
}  

Тогда ваш тестовый код будет работать почти так же, как и исходный:

MyThreadPool threadPool;
start(threadPool, new MyTask(threadPool));
threadPool.waitForDone();
// ... rest of the code
...