Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

Problem running tests that use Sqlite, assembly not found
MarcChu
#1 Posted : Friday, September 26, 2014 6:23:59 PM(UTC)
Rank: Member

Groups: Registered
Joined: 9/26/2014(UTC)
Posts: 22

Thanks: 3 times
Was thanked: 1 time(s) in 1 post(s)
I'm using Sqlite to try to setup my integration tests to use an in-memory DB. I have a TestHelpers assembly that references Sqlite (installed with Nuget), and which uses Autofac to resolve my DAL. I have many test projects that reference the TestHelpers project. Whenever I try to run an integration test that exercises the code that resolves my DAL, I get the following exception:

System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
----> System.DllNotFoundException : Unable to load DLL 'SQLite.Interop.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

If I manually copy this file into the workspace bin directory of my tests, then this exception goes away.

I've attempted to resolve this problem by adding this file to the General->Additional files to include setting, but this doesn't seem to be doing anything. If I check the workspace directory, SQLite.Interop.dll still isn't there. This isn't optimal anyways, because I don't want to have to include this file as an "Additional file to include" in every test project. I tried doing this for the TestHelpers project, but that doesn't seem to do anything either. The only assembly that ends up in my workspace bin directory is my specific test assembly.

The only solution to this that I've found is to include the SQLite.Interop.dll assembly in the TestHelpers project as content, set it to copy only, then change the integration test Build Settings->Copy referenced assemblies to workspace. This will put all necessary file into the test's bin workspace bin directory so that it can be found, as well as every other referenced assembly, "at the expense of build performance". And I will have to manually do this for every test project, which I don't want to have to do.

So the question is.... Is there any better way to do this? Why isn't the "Additional files to include" setting working to do what I want?
Remco
#2 Posted : Friday, September 26, 2014 10:29:17 PM(UTC)
Rank: NCrunch Developer

Groups: Administrators
Joined: 4/16/2011(UTC)
Posts: 7,144

Thanks: 959 times
Was thanked: 1290 time(s) in 1196 post(s)
Assuming you have a reference to SQLite.Interop.dll somewhere in your code, this is a problem that should be solvable with just the 'Copy referenced assemblies to workspace' setting.

Note that this setting only applies itself to the project you set it on, which in some cases isn't enough. If you are working with a reference sitting at the bottom of a dependency chain, the setting needs to be turned on for all projects in the chain. If in doubt, try turning it on for your entire solution (just select all the projects in the window). Depending on whether this works, you can then selectively turn off the setting for the projects that don't need it.

The 'Additional files to include' setting isn't intended to be used to help solve assembly referencing issues. In some cases you can rig up solutions using this setting, but there will be side effects involved and it will create a dependency on your foreground build. If you want to try and get away from using the 'Copy referenced assemblies to workspace', you'll probably need to revisit how the assembly is being loaded. Autofac may box you away from this, but sometimes you can work around the box by pre-loading the reference manually using Assembly.LoadFrom in combination with the methods on the NCrunch Environment class which can obtain the workspace locations of dependencies during test run-time.

Depending on the behaviour of Autofac, it may also be enough to simply turn on the Pre-load assembly references setting as this will force the SQLLite assembly to be in the application domain before Autofac tries to load it.
1 user thanked Remco for this useful post.
nCubed on 10/13/2014(UTC)
MarcChu
#3 Posted : Monday, September 29, 2014 1:38:29 PM(UTC)
Rank: Member

Groups: Registered
Joined: 9/26/2014(UTC)
Posts: 22

Thanks: 3 times
Was thanked: 1 time(s) in 1 post(s)
Well, this particular assembly is a strange beast. It's an unmanaged assembly, so I'm not sure that it even can be referenced. SQLite has a special build target that will copy this assembly into a sub-directory in the bin directory of the project (actually, it does this twice, once for x86 and once for x64). I'm not even entirely sure how this is supposed to be handled. There seems to be a lot of confusion around it. One may have to manually copy/move the .dll into the bin root in order for it to be found and used. That's the reason that I included it as 'content' in my TestHelpers project, and set it to copy always.

But I guess the bottom line is that all of my individual test projects will have to 'Copy referenced assemblies' (and only if they happen to be integration tests, which are the only ones that will be using this feature). The only reason I don't like this solution is that it's opaque. Since this is a per-user setting, I can imagine people on my team running into this over and over, and having to re-discover the solution. Intuitively, referencing the TestHelpers project is the only thing that one should have to do in order to be able to use its capabilities. In my experience, trying to document something like this is useless, as the documentation is never found and usually never even checked.

So is there any better way to make this as transparent as possible?
Remco
#4 Posted : Monday, September 29, 2014 10:49:58 PM(UTC)
Rank: NCrunch Developer

Groups: Administrators
Joined: 4/16/2011(UTC)
Posts: 7,144

Thanks: 959 times
Was thanked: 1290 time(s) in 1196 post(s)
Ok - so basically this file is a content resource then rather than a .NET assembly reference. That makes sense.

This then becomes a bit more complicated, as the special build step used by SQLite will work around normal build logic, and NCrunch's 'Copy Referenced assemblies to workspace' setting likely won't detect the file in its copied (bin) location.

Including the DLL as a content file inside the TestHelpers project should in theory allow you to solve this. As long as the file is set to be copied to the output directory, it can then be resolved by the TestHelpers assembly at runtime. Turning on the 'Copy referenced assemblies to workspace' setting for dependent test projects will allow NCrunch to copy the file into the bin directories of these projects and should allow it to be resolved normally.

The 'Copy referenced assemblies to workspace' setting is stored inside the .ncrunchproject file, which is intended to be shared with the rest of your team via VCS (see http://www.ncrunch.net/documentation/considerations-and-constraints_using-ncrunch-with-source-control). As long as you check in and share this file, your team should have no problem getting NCrunch to work without needing specialised knowledge on why the setting is being used.

I do feel that much of this problem stems from the logic being used to resolve the SQLite assembly. Technically, this logic should be checking for the assembly in the same directory as the TestHelpers assembly. If you're able to make sure this is the case, you can then solve this problem without using the 'Copy referenced assemblies to workspace' setting, which will also help with your build performance.
Brannon
#5 Posted : Thursday, October 2, 2014 3:14:22 PM(UTC)
Rank: Newbie

Groups: Registered
Joined: 6/26/2014(UTC)
Posts: 6
Location: United States of America

SQLite (via Nuget) recently changed their native file deployment. They used to add the native files to the csproj file as content that was copied when newer. However, it appears that their current package copies the files as part of the Nuget dependency verification step during compilation. This makes it hard for NCrunch as NCrunch only copies files it sees as relevant to the csproj to a temp folder.

I was able to work around this issue using the "Additional files to include". It required that I manually compile the project at least once after getting the Nuget package. I added a path that looks like this:
bin\*\x*\*.dll

Perhaps NCrunch could run some nuget validation command for a project file as part of its build?
Remco
#6 Posted : Thursday, October 2, 2014 8:48:26 PM(UTC)
Rank: NCrunch Developer

Groups: Administrators
Joined: 4/16/2011(UTC)
Posts: 7,144

Thanks: 959 times
Was thanked: 1290 time(s) in 1196 post(s)
Brannon;6492 wrote:
Perhaps NCrunch could run some nuget validation command for a project file as part of its build?


NCrunch did originally do this, but it created problems with increased build times and unnecessary download actions into the workspaces. As long as you've always run your foreground build after a fresh VCS checkout, NCrunch should be able to resolve the references and continue as usual.

Your fix will work correctly, although it does create a further dependency on the foreground build. It may be possible to disable the SQLite file copying step using an NCrunch build override, then specifying the file as content should allow NCrunch to copy it as normal ... but this is a more complex solution, so it's entirely up to you as to which approach you find easier. Often messing around with Nuget package build scripts can create problems the next time the Nuget package is updated by the vendor.
1 user thanked Remco for this useful post.
MarcChu on 10/20/2014(UTC)
Users browsing this topic
Guest
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

YAF | YAF © 2003-2011, Yet Another Forum.NET
This page was generated in 0.058 seconds.
Trial NCrunch
Take NCrunch for a spin
Do your fingers a favour and supercharge your testing workflow
Free Download