2

I am having trouble with my Visual Studio (2010) Unit Tests.

Whenever anything goes wrong and an exception of one type is thrown, the UnitTestAdapter throws SerializationExceptions, telling me he can't deserialize the Exceptions thrown.

In the Unit Tests I created, these are mostly either System.Data.SqlServerCe.SqlCeException or NHibernate.MappingException.

I cannot figure out why this is happening. Research told me, that the most common reason is that the Assemblies where these types reside is not available to the UnitTestAdapter, but when I look into the TestResults-folder, I see every assembly needed, including System.Data.SqlServerCe.dll and Nhibernate.dll.

So - what can I do to debug this? I need to see the exceptions in the test results for them to be useful in any way.

leppie
  • 115,091
  • 17
  • 196
  • 297
F.P
  • 17,421
  • 34
  • 123
  • 189

2 Answers2

2

When running Visual Studio Unit Tests, VSTestHost is the process that initializes and runs the test.

A new AppDomain gets created and the base directory for the AppDomain gets set to the unit test "Out" directory that contains all the assemblies and dependencies required to run the test.

The test directory is called "TestResults" and is found in the same directory where the solution file resides. Within the "TestResults" directory you will find a bunch of sub-directories for every test run.

Once the Unit Test has completed, the executing thread returns to the default AppDomain for the VSTestHost process. Part of the process for returning to the default AppDomain is to de-serialize objects in it’s calling context. However, the BaseDirectory has already been reset back to the directory containing the VSTestHost executable which is "C:\Program Files\Microsoft Visual Studio {version}\Common7\IDE".

This then cause the de-serialization to fail since the type being de-serialized cannot be found in the VSTestHost directory. The exception reads something along the lines of:

Unit Test Adapter threw exception: Type is not resolved for member 'xxx,xxx, Version=2.0.3370.22002, Culture=neutral, PublicKeyToken=null'

A possible hack could be create a directory in "C:\Program Files\Microsoft Visual Studio {version}\Common7\IDE" called "UnitTestAssemblies". copy all the required assemblies into this directory. Then manually edited the VSTestHost configuration file called "VSTestHost.exe.config" to include the directory created as part of it’s probing path:

<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
 <probing privatePath="PrivateAssemblies;PublicAssemblies;UnitTestAssemblies"/>
</assemblyBinding>

This will then force a lookup into the directory created for any missing types during de-serialization.

EDIT

Since semms an assembly binding issue Iam suggest you to try Assembly Binding Log Viewer (Fuslogvw.exe) to analyze the resource loading process, so I hope you will discover the arcane nature of your issue

ale
  • 10,012
  • 5
  • 40
  • 49
  • Okay, I understand this and will try it. But why is this even necessary? It feels like a real nasty hack. Shouldn't this work out-of-the-box already? I know I created UnitTests for some other project and never ran into this problem. – F.P Jul 01 '14 at 06:18
  • @FlorianPeschka seems a know issue http://social.msdn.microsoft.com/Forums/en-US/f6325a92-0231-45f3-92a5-176cc45691ad/unit-test-issue-since-upgrade?forum=vststest or else http://social.msdn.microsoft.com/Forums/en-US/81814766-a522-4a19-8575-7bc7f581623c/assembly-not-found-serialization-exception?forum=vststest – ale Jul 01 '14 at 07:39
  • Interesting. I wonder why I have some projects where this works perfectly fine. Must have something to do with the project setup, right? – F.P Jul 01 '14 at 08:02
  • In the thread you linked, they say that *"We are going to fix this issue in Visual Studio SP1."* and this was posted in 2008. Is it really still the same issue in VS 2010? I can hardly believe that? – F.P Jul 01 '14 at 08:13
  • Unfortunately, it doesnt. I copied all the dlls from the `bin\Debug` folder of the project to the new folder, edited the `config` and restartet VS before running the tests. The error is still `The constructor to deserialize an object of type [...]SqlCeException was not found.` – F.P Jul 01 '14 at 09:42
  • 1
    @FlorianPeschka I'm sorry, I've found an interesting link http://connect.microsoft.com/SQLServer/feedback/details/356397/sqlceexception-marked-with-serializable-but-isnt-serializable I'd like know if has been fixed, are you sure System.Data.SqlServerCe.dll is in your copied folder? – ale Jul 01 '14 at 10:20
  • I just installed the v4.0 of the SQL Server Compact and used the DLL of that in the UnitTests, now it seems at least that error is fixed, because now the message reads *"Type is not resolved for member 'NHibernate.HibernateException"*. I just noticed that I do not have a `VSTestHost.exe.config` in the `IDE` folder as you mentioned for me to edit. Where do I find this file? – F.P Jul 01 '14 at 11:37
  • 1
    I found the problem. It's something completely different. Thanks for your great input though! – F.P Jul 01 '14 at 12:09
1

Well, after a good amount of man-hours wasted, I stumbled upon the solution. More or less...

This post pointed me in the direction, more specifically the quote

To recap, MyCustomException was thrown at very early stage of test execution. The dll that contained it was not loaded yet so Unit Test Adapter indeed could not reach it.

I use a custom base class to initialize my UnitTests that need database connections. This base class has a normal constructur that does not have ClassInitialize, because [ClassInitialize] is not called by the UnitTestAdapter when it's in subclasses:

public DatabaseAware()
{
    XmlConfigurator.Configure();

    _logger.Info("Configuring NHibernate");
    _configuration = new Configuration().Configure();
    _sessionFactory = _configuration.BuildSessionFactory();
}

So, upon invoking the constructor, if anything goes wrong, the execution of everything is apparently halted.

Curiously enough, this includes loading assemblies. So, by the time my constructor threw an Exception, the Assembly for NHibernate was not yet loaded, resulting in a Type is not resolved for member NHibernate.HibernateException message.

What a ride. Basically, all I did now is to introduce an exception handling in the constructor to fail if anything goes wrong:

public DatabaseAware()
{
    XmlConfigurator.Configure();

    try
    {
        _logger.Info("Configuring NHibernate");
        _configuration = new Configuration().Configure();
        _sessionFactory = _configuration.BuildSessionFactory();
    }
    catch (Exception ex)
    {
        _logger.Fatal(ex);
        Assert.Fail(ex.Message);
    }
}

Now, I can run the tests as before without any problems. (Or, at least, when a problem occurs in the constructor, I will be notified of it).

F.P
  • 17,421
  • 34
  • 123
  • 189