Yes, you can wire up to the signals that show a test session (the tab in the runner window) opening + closing, and for each session, when tests are run and what the results are. You can see it being done here, as part of the Clippy extension:
https://github.com/citizenmatt/resharper-clippy/blob/master/src/resharper-clippy/src/UnitTestAnimations.cs
It uses the IUnitTestSessionConductor interface to wire up to the SessionOpened and SessionClosed signals, and for each session, listens for changes to the session's Launch property, which is what describes the tests being run. When the Launch changes, it subscribes to the Launch's State property, which tells us when the session is running, aborting, stopping, idle, and so on. Once we know that the session completes, you can use the IUnitTestResultManager to get at the results themselves.
The code makes good use of the Lifetime construct to manage how long the subscriptions last. The main component gets a Lifetime that is scoped to the solution, and this is used to subscribe to the SessionOpened/SessionClosed signals. When a session is opened, a new Lifetime is created, as a child of the component's lifetime (so if the solution closes, this new child lifetime is also terminated). This new lifetime is stored in a dictionary, and terminated when SessionClosed fires. The Launch property uses SequentialLifetimes, which maintains a single lifetime and automatically terminates the previous one when creating the next new one.
Hope that makes sense!
Regards
Matt