2010-09-02 1 views
2

У меня проблема с QEventLoop. Я хочу создать «TimeBoundExerciser» для моего модульного теста, чтобы мой SUT, который блокирует QEventLoop, не будет блокировать остальные тестовые примеры. В частности, мой тестовый пример - убедиться, что SUT завершает работу после таймаута.Почему мой вложенный QEventLoop не передает все события для моего QThread?

TimeBoundExerciser в основном порождает поток, выполняет SUT в этом потоке, ждет завершения потока и, если он не завершится через определенное время, вызывает метод quit() в потоке через QMetaObject :: invokeMethod() и QueuedConnection. Я ожидал бы, что выполнение quit() вызовет выход моего вложенного QEventLoop, завершив мой поток. Однако я обнаружил, что метод quit() никогда не вызывается, и поток никогда не заканчивается. Код для моего TimeBoundExerciser ниже: Метод

class IExerciseTheSystem 
{ 
    void operator()() = 0; 
}; 

class TimeBoundExerciser : private QThread 
{ 
Q_OBJECT 
public: 
    enum CompletionType 
    { 
     TERMINATED, 
     FORCE_QUIT, 
     QUIT 
    }; 
    TimeBoundExerciser(const IExerciseTheSystem& exerciser); 
    CompletionType exercise(unsigned long timeoutMillis); 
protected: 
    void run(); 

protected slots: 
    void exerciseTheSystem(); 
private: 
    const IExerciseTheSystem& exerciser; 
}; 

TimeBoundExerciser::TimeBoundExerciser(const IExerciseTheSystem& exerciser) : exerciser(exerciser) 
{ 

} 

TimeBoundExerciser::CompletionType TimeBoundExerciser::exercise(unsigned long timeoutMillis) 
{ 
    start(); 
    while (!isRunning()) 
    { 
     msleep(10); 
    } 

    moveToThread(this); 

    wait(timeoutMillis); 
    if (!isFinished()) 
    { 
     bool quitResult; 
     QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection, Q_RETURN_ARG(bool, quitResult)); 
     wait(); 
     return FORCE_QUIT; 
    } 

    return QUIT; 
} 

void TimeBoundExerciser::run() 
{ 
    setTerminationEnabled(true); 
    QMetaObject::invokeMethod(this, "exerciseTheSystem", Qt::QueuedConnection); 
    exec(); 
} 

void TimeBoundExerciser::exerciseTheSystem() 
{ 
    cout << "Starting exerciser" << endl; 
    exerciser(); 
    cout << "Exerciser ended" << endl; 
} 

упражнения() выполняется в главном потоке, чтобы начать весь процесс.

+0

Вы когда-нибудь видели выход из exerciseTheSystem()? –

+0

Я вижу «Запуск тренажера», но не «Тренажер закончился». – gregsymons

+0

Что происходит в тренажере()? Это когда-нибудь заканчивается? –

ответ

0

Если тест проходит слишком долго, это, вероятно, какие-то данные обработки цикла.

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

+0

Кроме того, поскольку я управляю кодом, я знаю, что тестовый поток занят запуском локального QEventLoop, а не некоторой долговременной обработкой. SUT в основном ждет своего вызова QEventLoop :: exec() для выхода. – gregsymons

+0

Думал, что вы сказали, что это единичный тест. Ввод бесконечного цикла - это полностью возможный способ отказа от тестирования, и что-то, что ваш пакет тестирования продукта должен обнаружить. –

+0

Это так. В основном, тестируемый блок создает локальный QEventLoop и выполняет его до тех пор, пока не получит определенный сигнал, после чего локальный QEventLoop выйдет и вернется к вызывающему. По существу, я создаю модальный объект, подобный модальному диалоговому окну, за исключением того, что он будет иметь таймаут. Единичный тест, который я пишу, который использует TimeBoundedExerciser, предназначен для проверки того, что объект выходит из цикла событий правильно, когда тайм-аут проходит. – gregsymons

Смежные вопросы