9

I don't know how to specify correct mask to search for my test assemblies in TFS2010 build definition. I'm not using default Binaries folder for output assemblies. Each test project has its own bin\Debug or bin\Release output folder. If I use the default mask **\*test*.dll my tests failed with this error:

API restriction: The assembly 'file:///E:\Builds\....\obj\Debug\xxx.IntegrationTests.dll' 
has already loaded from a different location. It cannot be loaded from a new location within the same appdomain.

This is because **\*test*.dll mask will find multiple results for the same assembly in the bin\Debug and obj\Debug folders.

I tried to change this mask to exclude obj\Debug folder and use bin only:

**\bin\Debug\*test*.dll
**\bin\**\*test*.dll
**\Debug\*test*.dll

but FindMatchingFiles activity return always 0 results.

It is working only when I pass full path to the test assembly.

What is the correct mask if I want to exclude obj\Debug folders from test assembly search?

WORKAROUND:
I'm still using FindMatchingFiles activity, but I had to add Assign activity with following params:

To - testAssemblies
From - testAssemblies.Where(Function(o) Not o.Contains("\obj\")).ToList()

I'm filtering all test assemblies found in the "obj" folders this way.

Ludwo
  • 6,043
  • 4
  • 32
  • 48

5 Answers5

4

The build activity that is of interest to you is named "Find Test Assemblies": enter image description here

So, what you place at the build definition is concatenated after build script variable outputDirectory.

This outputDirectory is initialized for each configuration in activity "Initialize OutputDirectory": enter image description here

You can queue a new build where you set your 'Logging Verbosity' equal to Diagnostic. Once this has ran (and failed), check for what is going on with your build.

My guess is that you have issues with your configuration/platform settings, but without concrete input that's just guessing.

pantelif
  • 8,524
  • 2
  • 33
  • 48
  • You're right. testAssemblies collection is filled by "Find Test Assemblies" activity. I have foreach activity after this activity to log content of testAssemblies collection. If I use **\*test*.dll mask, result is OK, but with duplicate test assemblies from bin and obj folders. I tried to filter it by using different masks, but it seems I'm using wrong mask. testAssemblies collection was always empty. I can filter it in the code as a workaround... – Ludwo Nov 15 '11 at 19:52
1

I ran into basically the same issue that you have. I have developers using a helper test assembly (TestHelper) and a _PublishedWebsites folder that was causing this issue.

What I ended up doing to fix this was solve the problem of getting multiple of the same test DLL passed to MSTest. "Well, that's what I'm trying to do with my mask," you may think! I tried that same solution but came up empty.

I wrote a custom task and inserted it after the build process finds the test assemblies. Here's the code for the custom task:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Build.Workflow.Activities;
using System.Activities;
using System.IO;

namespace BuildTasks.Activities
{
  [BuildActivity(HostEnvironmentOption.All)]
  public class DistinctFileList : CodeActivity<IEnumerable<String>>
  {
    public InArgument<IEnumerable<String>> ListIn { get; set; }

    protected override IEnumerable<String> Execute(CodeActivityContext context)
    {
      IEnumerable<string> listIn = context.GetValue(this.ListIn);

      context.TrackBuildMessage("Items in ListIn: " + listIn.Count(), BuildMessageImportance.High);

      var filenameGroupings = listIn.Select(filename => new FileInfo(filename.ToString()))
        .GroupBy(fileInfo => fileInfo.Name);

      IEnumerable<string> listOut = filenameGroupings.Select(group => group.FirstOrDefault().FullName);

      context.TrackBuildMessage("Items in out list: " + listOut.Count(), BuildMessageImportance.High);

      string multiples = string.Join(", ",
        filenameGroupings.Where(group => group.Count() > 1).SelectMany(group => group.Select(fileInfo => fileInfo.FullName)).ToArray());

      context.TrackBuildMessage("Duplicate test items: " + multiples, BuildMessageImportance.High);

      return listOut.ToList();
    }
  }
}

You'd insert this after the "Find Test Assemblies" task.

Mike G
  • 1,956
  • 1
  • 30
  • 62
  • Hi Mike. I'm using Assign activity after FindMatchingFiles activity with Linq query to filter FindMatchingFiles results. I added workaround section to my question. – Ludwo May 15 '12 at 06:09
  • Ok, that's basically what I'm doing here. I'm just doing a bit more indepth check. I check the filenames and not the full path. I also output a bit of "debug" information. I'm glad we came to the same conclusion. Makes me feel better about this method! – Mike G May 15 '12 at 14:10
  • I wrote a program that allows you to test your searchpatterns against FindMatchingFiles and posted it to this thread: http://stackoverflow.com/questions/4524910/use-matchpattern-property-of-findmatchingfiles-workflow-activity/24408935#24408935 – invalidusername Jun 25 '14 at 12:43
1

I'm still using FindMatchingFiles activity, but I had to add Assign activity with following params:

To - testAssemblies From - testAssemblies.Where(Function(o) Not o.Contains("\obj\")).ToList() I'm filtering all test assemblies found in the "obj" folders this way.

Ludwo
  • 6,043
  • 4
  • 32
  • 48
0

I ran into this issue but found that rather than just bin and obj containing duplicates, I had many copies of the same DLLs appearing in various project folders.

Ludwo's answer with Assign was nearly enough to fix it, but for my situation I needed a more general value for the From parameter. This VB groups the discovered file paths by file name, and then picks the first path from each group. It of course will only work if and only if each file name maps to one logical DLL:

testAssemblies.GroupBy(Function(a) New System.IO.FileInfo(a).Name).[Select](Function(g) g.First())
0

Probably the ** at the beginning of your filter is the problem. The starting point of the search is at a location you would not expect it to be and subdirectories do not contain your test files.

To troubleshoot this problem, please add ..\..\.. to the start of your filter expression. For debugging purposes, this will get out of the subdirectory structure you're in and perform a wider search on your system for the test files. You can also make the first part absolute, to make sure you're searching in the right directory subtrees.

As alternative, you can also run a processmonitor session on your build system, to see where your TFS build engine is actually looking for your test assemblies. Or perform some logging in the build workflow / activity itself.

When you have found the problem, narrow your search window again to not search irrelevant subdirectory structures.

kroonwijk
  • 8,340
  • 3
  • 31
  • 52
  • I tried it but the results are still the same. I changed search mask to "..\..\..\\**\.Unittests.dll". Additional test assemblies were found from other builds. Then I changed search mask to ""..\..\..\\**\bin\\**\.Unittests.dll" and no test assemblies were found. – Ludwo Nov 23 '11 at 14:29
  • Can you then try with Process Monitor running on your build system. I am curious where it searching for your files. And please post the part of the subdirectory structure your test assemblies are in. We might be able to discover why your pattern does not match. – kroonwijk Nov 23 '11 at 19:11
  • Adding to this answer as it took me a while to find out which process to actually monitor - it is **TfsBuildServiceHost.exe**. – Gorgsenegger Jul 30 '15 at 09:18