17


I have a unit test method which tests a controller action method. The action method uses resource file to get a static message.

 message = Resources.MyResource.MemberNotVerified;

However at this line the exception thrown is :-

"Could not load file or assembly 'App_GlobalResources' or one of its dependencies. The system cannot find the file specified.":"App_GlobalResources" System.IO.IOException {System.IO.FileNotFoundException}

I tried coping the whole resource file in my Test project, but it was unsuccessful.
Any idea friends.

tereško
  • 58,060
  • 25
  • 98
  • 150
SocialCircus
  • 2,110
  • 6
  • 24
  • 35

3 Answers3

21

Behind the scenes, App_GlobalResources uses HttpContext.GetGlobalResourceObject

Of course, there is no HttpContext in unit tests (unless your mocking it).

If you were so inclined to mock it, Phil Haack has a decent post on it here.

There is another solution, and that is to move the RESX files out of the regular directory.

Scott Allen has a post on that here.

RPM1984
  • 72,246
  • 58
  • 225
  • 350
  • 1
    That's Scott Allen, not Scott Guthrie :) – OdeToCode Nov 11 '10 at 20:49
  • 1
    @OdeToCode - damn, edited - and i had to remove my punchline. :) – RPM1984 Nov 11 '10 at 22:48
  • 1
    First tried the Simulator from Haack, but that didn't work out for me (quickly enough). Definitely read Scott's post! Conclusion: don't use special folders (like App_GlobalResources) – Jowen Jun 04 '14 at 12:15
  • 1
    I don't understand how the Haack solution is meant to solve the problem, he doesn't give an example of stubbing a resource files, just stubbing httpcontext which has a well known solution. Can anyone provide an example. I can't use the Scott Allen approach. – johnstaveley Jan 03 '18 at 05:52
4

An alternative approach is to change the type of resource file your generating.

I expect there are other ways of setting it up but we set the following settings in the file's properties (right click on the file in the solution explorer and select properties):

  • Build Action: Embedded Resource
  • Copy to Output Directory: Do not copy
  • Custom Tool: PublicResXFileCodeGenerator
  • Resources: Resources
Patrick
  • 8,175
  • 7
  • 56
  • 72
  • 1
    Nice idea, but it has one drawback: When publishing your web application, the file is no longer copied, causing `<%$ Resources:... %>` expressions to fail. You will need to *manually* copy the files after each deployment. – Heinzi Feb 18 '16 at 09:11
  • @Heinzi: We use msdeploy via jenkins and all files are deployed correctly without any extra bits to ensure the resource files are copied across – Patrick Jan 09 '19 at 14:16
  • Ha - only a year too late :) – Patrick Jan 09 '19 at 14:16
2

Here's a solution that doesn't require changing anything, as it will generate an assembly named App_GlobalResources.dll with all the resources embedded, the way the tests expect.

Just call it from a method marked with the AssemblyInitialize attribute and it will run only once, before all tests start:

public static void GenerateResourceAssembly()
{
    var testExecutionFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

    var solutionRootPath = "PATH_TO_YOUR_SOLUTION_ROOT";

    //Somewhere similar to C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin
    var pathResgen = "PATH_TO_RESGEN.EXE"; 

    //You may need to adjust to the path where your global resources are
    var globalResourcesPath = Path.Combine(solutionRootPath, @"Web\App_GlobalResources");

    var parameters = new CompilerParameters
    {
        GenerateExecutable = false,
        OutputAssembly = "App_GlobalResources.dll"
    };

    foreach (var pathResx in Directory.EnumerateFiles(globalResourcesPath, "*.resx"))
    {
        var resxFileInfo = new FileInfo(pathResx);

        var filename = resxFileInfo.Name.Replace(".resx", ".resources");

        var pathResources = Path.Combine(testExecutionFolder, "Resources." + filename);

        var startInfo = new ProcessStartInfo
        {
            CreateNoWindow = true,
            WindowStyle = ProcessWindowStyle.Hidden,
            FileName = Path.Combine(pathResgen, "resgen.exe"),
            Arguments = string.Format("\"{0}\" \"{1}\"", pathResx, pathResources)
        };

        using (var resgen = Process.Start(startInfo))
        {
            resgen.WaitForExit();
        }

        parameters.EmbeddedResources.Add(pathResources);
    }

    CodeDomProvider.CreateProvider("CSharp").CompileAssemblyFromSource(parameters);
}
Anderson Pimentel
  • 5,086
  • 2
  • 32
  • 54