Intercepting the start/end of a Unit Test Session

Hi,

I have a few pre-steps and post steps i'd like to perform before the resharper unit test session (containing my collection of tests i've chosen to run) is run, and right after it has completed running.
Is there any way i can achieve this?

Thanks,
Paul

9 comments
Comment actions Permalink

There's nothing built-in to allow you to do this, but you could write a plugin to do it - you can get more info on plugins here: http://confluence.jetbrains.com/display/NETCOM/ReSharper+Plugin+Development

The IUnitTestSession interface exposes a Launch property that you can subscribe to, and it will notify you every time it changes. You can then subscribe to each new Launch's State property, and you'll be notified when the state is Starting, Stopping, Aborting, etc. This should give you the chance to do what you need to, as long as it's something simple that can run in the current thread.

Here's a very rough outline:

[SolutionComponent]
public class MyUnitTestMonitor
{
  public MyUnitTestMonitor(IUnitTestSessionManager sessionManager)
  {
    sessionManager.SessionCreated.Advise(lifetime, sessionView => {
      sessionView.Session.Launch.Advise(lifetime, launch => {
        if (launch.HasNew && launch.New != null) {
          launch.New.State.Change.Advise(lifetime, state => {
            if (state.HasNew && state.New == UnitTestSessionState.Starting)
              // ...
            if (state.HasNew && state.New == UnitTestSessionState.Stopping)
              // ...
          };
        }
      });
    });
  }
}

0
Comment actions Permalink

Thanks Matt, thats a helpful example
I've downloaded the latest SDK and am having a go with the sample code you provided but having a few build issues:

sessionView.Session.Launch.Advise(... - Advise method doesnt exist which causes a bunch of build errors within the other lambda expressions.
Launch is of type IProperty<IUnitTestLaunch> but im not sure how to get code successfully building.
regards,
Paul

0
Comment actions Permalink

My mistake. That should have been sessionView.Session.Launch.Change.Advise. The Change property is of type ISignal<T>, which is conceptually similar to a .net event.

0
Comment actions Permalink

Hi Matt, thanks for your help, that worked great! :-) I'm wanting to take this one step further, we have a pretty big suite of integration tests all which rely on creating/tearing down a database per test which im working on some performance enhancements around this.

Ideally what i'd like to know is:

1. Within the test session  "Start" event of the plugin, is it possible for me to pass a generated variable from here, into the test context that is run in the tests?
2. If i change the resharper settings say to 4 assemblies in parallel, what would be the expected behaviour of the plugin if my tests are across 10 assemblies, would i expect the "starting" event to fire 10 times?

thanks
Paul

0
Comment actions Permalink

I'm not sure what you mean by passing a variable into the context - could you elaborate?

You should get one starting event, just for the session. The session has a "launch", and that launch is split into multiple "runs". Each run pretty much maps to an assembly, and these are executed in parallel. There are no events for these starting.

0
Comment actions Permalink

Maybe i reword that a little :-)

say i've got 1000 integration tests running with the option "12" parallel assemblies. The tests use a injected repository which sets up the connection string which always points to the same single database. What i want to do is to somehow get a specific test session id, append that to the database name that gets created on test execution, then pass that sessionId via IOC to the connection string, so the test knows which database it needs to connect to.

So what i was thinking is to grab the test session id from the resharper plugin, then somehow pass that through to wherever it creates the instance of the test session so within my test method:

[ClassInitialize()]
        public static void MyClassInitialize(TestContext testContext)
        {
            TestContext.Properties[...] =  ....;
            //somehow retrieve the test session ID from within here and use it to append to database name...
        }

Is that a bit clearer?

0
Comment actions Permalink

Unfortunately, you can't access the TestContext from a plugin. There's no ability to pass information from a plugin to a test run. If you're concerned about creating a new database for each run, can that code live in the tests themselves? Generate a random id for each test run?

0
Comment actions Permalink

Thanks Matt.
My setup is as follows:
1. integration test base class creates the required sqlite test database (with a fixed db name connection string), say "test.db", then copies it as "test_backup.db"
2. the actual integration test resolves an instance of my repository interface (the repository also stores the db connectionstring also).

I this case i'd need to create a temporary db name, then pass it into the IOC injection as a parameter so the repo can append the correct database name to the connection string.
Reason I want to do this is because at the beginning of the test session i want to create a empty sqlite db with schema, back the  file up, then after each test is run, overwrite the test db with the backup db, so i dont have to create the same schema every time after each test run.

0
Comment actions Permalink

I think this is probably something that is best handled in your own test code, to be honest. Your code will know if/when it's been called the first time in a session and can create the file at that time. The test code can also create a temporary file name during initialisation, and inject into the IoC before anything else is run. As I mentioned, it's not possible to get at the test context from a plugin, so you're not able to pass any information along - and the session id is usually just a guid, which you could just as easily create in your test code.

0

Please sign in to leave a comment.