使用QThreadPool并行运行单元测试任务

问题描述 投票:0回答:1

我正在使用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()不是虚拟的。编写测试的最佳方法是什么?

c++ qt unit-testing parallel-processing qthread
1个回答
0
投票

关于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
© www.soinside.com 2019 - 2024. All rights reserved.