Unit Test with catch C++

Hi,

I am trying to run some unit tests using Catch. I need to have the JUCE event loop running for these tests to work.

I am able to use juce::UnitTest. To do this, I create a
class JuceLexTests: public JUCEApplicationBase
then call a UnitTestRunner inside its void initialise method, and use the
START_JUCE_APPLICATION(JuceLexTests) macro.

However, I am not able to replicate this approach with catch.

Is it possible to run the JUCE event loop from unit tests in Catch?

Thanks.

1 Like

Did you try calling Catch::Session().run() inside the initialise method?

That did the trick. Thanks!

1 Like

Hi. After working on all tests that don’t need the event loop running, I am coming back to this. The approach above works to run these tests. However, the problem is that Catch::Session().run() doesn’t return until all tests are completed. This means that, if I call Catch::Session().run() inside the initialise method, this method doesn’t return until all tests are completed. The event loop only starts after initialise returns. Any idea on how to make this work? Thanks!

I also have the same issue when I use UnitTestRunner. Any hints one how to run unit tests that require the main event loop would be appreciated.

Would using the AsyncUpdater class solve the issue, calling Catch::Session.run() from within handleAsyncCallback? This would make sure the message loop was first running before running the unit tests

1 Like

Hi, thanks for the suggestion! I tried this, and although inizialise returns, the loop event thread doesn’t actually do anything until Catch is done. This means that any test that need the event loop using catch don’t work. I am not sure if this is a Catch or a JUCE issue.

Specify, this is what I have:

class AsyncCath : public AsyncUpdater {
public:
    virtual void handleAsyncUpdate() override {
        Catch::Session().run();
    }
};

And in the initialise methods in the JUCEApplication:

void initialise(const String &commandLineParameters) override {
        m_Catch->triggerAsyncUpdate();
        /// I added some code here that needs the event loop here to make sure this works.
        /// it only gets triggered once Catch returns, but this method (initialise) returns immediately,
        /// so I am not sure what's going on.
    }

So maybe there’s a need create AsyncCath on a different thread?

I know that this is a rather old thread, but maybe this still helps.
I’ve faced exactly the same issue and found a rather simple solution. Use this class:

#pragma once
#include <juce_core/juce_core.h>
#include <juce_events/juce_events.h>

class ScopedMessageThread : juce::Thread
{
public:
	ScopedMessageThread() : juce::Thread("message thread")
	{
		startThread();
		auto wasSignaled = semaphore.wait ();
		juce::ignoreUnused (wasSignaled);
	}

	~ScopedMessageThread()
	{
		juce::MessageManager::getInstance()->stopDispatchLoop();
	    stopThread (10);
	}

private:
    void run () override
    {
        initializer.reset(new juce::ScopedJuceInitialiser_GUI);
		semaphore.signal();
		juce::MessageManager::getInstance()->runDispatchLoop();
    }

	juce::WaitableEvent semaphore;
	std::unique_ptr<juce::ScopedJuceInitialiser_GUI> initializer;
};

like:

#include "catch2/catch.hpp"
#include "ScopedMessageThread.h"

TEST_CASE("foo")
{
    ScopedMessageThread t;
    REQUIRE_NOTHROW(somethingExecutingOnMessageThread());
}

Its still a bit tricky though, because you’ll need to use some WaitableEvents in order for your Catch-Thread not to end before the actual work on the message-thread is finished.

2 Likes