GSoC Status Update - Week 2
01 Jul 2013This is a status update for my Google Summer of Code 2013 project - implementing advanced statistics importers for Amarok. Please read the first post if you would like to know more about the project.
I didn't think writing tests could be so much fun! Neither did I think they could take me so much time. What I scheduled for the past week was "implementing the initial test suite for importers (exam week)," and it was supposed to be a fast & easy task, allowing me to focus on my exams. And yet after my last test that week I found myself spending every day intensively coding. Most of the time was spent on figuring out how to approach testing and writing the code to make that chosen approach possible; writing tests themselves actually was the fast & easy task I thought it to be.
At the end, I ran git diff --stat for my changes: 26 files changed, 1246
insertions(+), 69 deletions(-). I was surprised.
I managed to test things the way I wanted to. I created two test suites,
TestITunesImporter and TestFastForwardImporter, both inheriting from
TestImportersCommon, which holds common tests and utility functions. I
slightly modified both importers so that I could statically provide them with
arbitrary database paths to read from and arbitrary collections to write to -
one of my goals for this week was *not to modify existing importers in any major
way.
I created two collections: localCollection and fileCollection; the latter
fulfilling a role of FileTrackProvider, giving importers information about
tracks located at nonexistent paths; the former being the collection tracks were
synchronized to. To easily check, clear, and modify their contents I extended
capabilities of Collections::CollectionTestImpl class, which stores collection
in-memory. The 'init' and 'clean' test procedures take care of filling the
fileCollection with necessary data, clearing localCollection, and resetting
statistics after each test.
The code has no idea which importers it's dealing with, operating on
DatabaseImporter, a superclass of both. The tests don't know even that. A
test sets preconditions by modifying collections' contents, calls
blockingImport() method of TestImportersCommon, and then checks the
resulting state. An elegant, implementation-agnostic way, which fulfills my
second goal for the week: write tests for current importers in a way that would
make them easily reused for reimplemented importers. Done and done.
So here's something I learned that week: how to run an asynchronous task in Qt
and block until it's done. That's a useful thing for testing! Here's the full
implementation of blockingImport():
void
TestImportersCommon::blockingImport()
{
QScopedPointer<DatabaseImporter> importer( newInstance() );
QEventLoop loop;
connect( importer.data(), SIGNAL(importSucceeded()), &loop, SLOT(quit()), Qt::QueuedConnection );
connect( importer.data(), SIGNAL(importFailed()), &loop, SLOT(quit()), Qt::QueuedConnection );
connect( importer.data(), SIGNAL(importError(QString)), &loop, SLOT(quit()), Qt::QueuedConnection );
connect( importer.data(), SIGNAL(importFailed()), this, SLOT(importFailed()) );
connect( importer.data(), SIGNAL(importError(QString)), this, SLOT(importFailed()) );
importer->startImporting();
loop.exec();
}
And this is as personal as it gets when it comes to interacting with importers in tests. (As you can see, I'm playing with a new plugin for code snippets. Configuring it fully is yet another thing I have planned for later.)
You can check out my progress on my public Amarok clone. The branch is named
gsoc-importers.
Thanks for reading!