Ming
Ming

Reputation: 740

Unit test a static method that calls a static method using moq

As the title, the code itself as following

internal static class ThumbnailPresentationLogic
    {
        public static string GetThumbnailUrl(List<Image> images)
        {
            if (images == null || images.FirstOrDefault() == null)
            {
                return ImageRetrievalConfiguration.MiniDefaultImageFullUrl;
            }

            Image latestImage = (from image in images
                                 orderby image.CreatedDate descending
                                 select image).First();

            Uri fullUrl;

            return 
                Uri.TryCreate(new Uri(ImageRetrievalConfiguration.GetConfig().ImageRepositoryName), latestImage.FileName,
                    out fullUrl)
                    ? fullUrl.AbsoluteUri
                    : ImageRetrievalConfiguration.MiniDefaultImageFullUrl;
        }
    }

I don't want the unit test go through any methods in ImageRetrievalConfiguration class, so how can I mock ImageRetrievalConfiguration and pass it into ThumbnailPresentationLogic class ??

Upvotes: 0

Views: 2671

Answers (3)

Jonathan
Jonathan

Reputation: 2358

I am not sure that is possible through Moq I use Rhino Mocks. What I usually do in this situation is use Spring.NET and provide an alternative mock that I call in tests as apposed to the one in production. This works really well for me especially with areas that use external webservices, datasources or the situation your have raised.

You then Unit Test ImageRetrievalConfiguration seperatly and ensure it works as expected. MockImageRetrievalConfiguration can return results based on how you wish it to react in your testing environment. This will maximize your test converage with the flexibility of mocking.

    internal static class SpringApplicationContext
    {
        private static IApplicationContext applicationContext = null;

        static SpringApplicationContext()
        {
            applicationContext = ContextRegistry.GetContext();
        }

        public static IApplicationContext ApplicationContext
        {
            get { return applicationContext; }
        }
    }

   public interface IImageRetrievalData
   {
       string ImageRepositoryName{get;set;}
   }    

public interface IImageRetrievalConfiguration    
{
     IImageRetrievalData GetConfig();
}

public class MockImageRetrievalConfiguration : IImageRetrievalConfiguration    
{    
    public IImageRetrievalData GetConfig()
     {
         //mock implementation
     }
}

public class ImageRetrievalConfiguration : IImageRetrievalConfiguration    
{

    public IImageRetrievalData GetConfig()
     {
        //Concrete implementation
     }
}



//your code
internal static class ThumbnailPresentationLogic     
{         
          public static string GetThumbnailUrl(List<Image> images)
          {             
            if (images == null || images.FirstOrDefault() == null)                                         
            {                 
                return ImageRetrievalConfiguration.MiniDefaultImageFullUrl;             
            }              
            Image latestImage = (from image in images orderby image.CreatedDate descending select image).First();              
            Uri fullUrl;   

//Spring 
                IImageRetrievalConfiguration imageRetrievalConfig = (IImageRetrievalConfiguration)            SpringApplicationContext.ApplicationContext["ImageRetrievalConfiguration"];



            return Uri.TryCreate(new Uri(imageRetrievalConfig.GetConfig().ImageRepositoryName), latestImage.FileName, out fullUrl) ? fullUrl.AbsoluteUri : ImageRetrievalConfiguration.MiniDefaultImageFullUrl;         
          }     
} 

//This would be your testing configuration

  <spring>
    <context>
      <resource uri="config://spring/objects" />
    </context>
    <objects xmlns="http://www.springframework.net">
      <object name="ImageRetrievalConfiguration" type="Tests.MockImageRetrievalConfiguration, Tests" singleton="false" />
    </objects>
  </spring>

//This would be your production configuration

  <spring>
    <context>
      <resource uri="config://spring/objects" />
    </context>
    <objects xmlns="http://www.springframework.net">
      <object name="ImageRetrievalConfiguration" type="Web.ImageRetrievalConfiguration , Web" singleton="false" />
    </objects>
  </spring>

You can download the Spring.NET framework from http://www.springframework.net/

Upvotes: 0

Daniel Hilgarth
Daniel Hilgarth

Reputation: 174309

You can't do this with Moq, because you would need to intercept the call to the methods of this static class and that is something all "normal" mocking frameworks can't achieve, because they are working purely with type inheritance, automatic code generation and stuff like that.
Intercepting a call to a static method however needs other mechanisms.
Intercepting calls to .NET framework static classes can be done using Moles. I am not sure if it works with your own static classes though.
TypeMock Isolator works with all static classes but it is not free.

However, I really think, you should reconsider your architecture instead.

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1500515

How about you split the method into two - one of which takes a "base URI" and "default Url" and one of which doesn't:

internal static class ThumbnailPresentationLogic
{
    public static string GetThumbnailUrl(List<Image> images)
    {
        return GetThumbnailUrl(images,
           new Uri(ImageRetrievalConfiguration.GetConfig().ImageRepositoryName),
           ImageRetrievalConfiguration.MiniDefaultImageFullUrl);
    }

    public static string GetThumbnailUrl(List<Image> images, Uri baseUri,
        string defaultImageFullUrl)
    {
        if (images == null || images.FirstOrDefault() == null)
        {
            return defaultImageFullUrl;
        }

        Image latestImage = (from image in images
                             orderby image.CreatedDate descending
                             select image).First();

        Uri fullUrl;

        return 
            Uri.TryCreate(baseUri, latestImage.FileName, out fullUrl)
                ? fullUrl.AbsoluteUri
                : defaultImageFullUrl;
    }
}

Then you can test the logic in the "three-parameter" overload, but the public method doesn't really contain any logic. You won't get 100% coverage, but you'll be able to test the real logic involved.

Upvotes: 3

Related Questions