简体   繁体   中英

How to unit test controller with WebImage in ASP. Net MVC App

I have this very simple method in an MVC controller:

    public void GetProfileImage(int id)
    {
        var data = _companyService.GetProfileImage(id);

        if (data == null)
            return;

        var image = new WebImage(data).ResizeMaxPreserveTransparency(250, 250);
        image.Write();
    }

Does anyone have any suggestions for how I can test this, mock the WebImage, or refactor it to be more testable? Thanks.

Few points:

  1. The method name starts with "Get" and method does not return anything.
  2. As you are updating the image inside GetProfileImage you ought to test whether those update are done correctly or not. That's one of the case you will write unit test against.
  3. In order to test the method behavior (eg image max transparency is set to 250) you should be returning the image object.

Hope this helps.

I spent way too long on this, but it was a very good learning experience for me. Here's how I did it:

1) Create an interface which wraps the methods and properties of WebImage that I need:

 public interface IWebImage
 { 
    void Write(string requestedFormat = null);

    string ImageFormat { get; }

    int Width { get; }

    int Height { get; }

    byte[] GetBytes(string requestedFormat = null);

    IWebImage Resize(int width, int height, bool preserveAspectRatio = true, bool preventEnlarge = false);
}

2) Create a wrapper which implements this interface, and is a wrapper for an actual WebImage:

 public class WebImageWrapper : IWebImage
 {
    private readonly WebImage _instance;

    public WebImageWrapper(byte[] data)
    {
        _instance = new WebImage(data);
    }

    public WebImageWrapper(WebImage image)
    {
        _instance = image;
    }

    public void Write(string requestedFormat = null)
    {
        _instance.Write(requestedFormat);
    }

    public string ImageFormat { get { return _instance.ImageFormat; } }

    public int Width { get { return _instance.Width; } }

    public int Height { get { return _instance.Height; } }

    public byte[] GetBytes(string requestedFormat = null)
    {
        return _instance.GetBytes(requestedFormat);
    }

    public IWebImage Resize(int width, int height, bool preserveAspectRatio = true, bool preventEnlarge = false)
    {
        return new WebImageWrapper(_instance.Resize(width, height, preserveAspectRatio, preventEnlarge));
    }
}

3) Create an interface for a factory which can be mocked to provide a mocked IWebImage, or can be injected to provide an actual WebImageWrapper.

public interface IWebImageFactory
{
    IWebImage Get(byte[] data);
}

4) The real implementation of this factory interface, which will be injected into the controller by Ninject, looks like this:

public class WebImageFactory : IWebImageFactory
{
    public IWebImage Get(byte[] data)
    {
        return new WebImageWrapper(data);
    }
}

5) Finally, my controller method now looks like this:

    public void GetProfileImage(int? id)
    {
        var data = _companyService.GetProfileImage(id);

        if (data == null)
            return;

        var image = WebImageFactory.Get(data).ResizeMaxPreserveTransparency(250, 250);
        image.Write();
    }

6) WebImageFactory is an injected property, so I can provide any mock I want, which in turn can provide a mocked IWebImage. From this point on, creating a unit test is trivial.

    [TestMethod]
    public void GetProfileImageTest()
    {
        // Arrange
        var byteArray = new[] {(byte) 12, (byte) 13};
        var image = new Mock<IWebImage>();
        var factory = new Mock<IWebImageFactory>();
        var companyService = new Mock<ICompanyService>();

        companyService.Setup(c => c.GetProfileImage(99)).Returns(byteArray);
        factory.Setup(f => f.Get(byteArray)).Returns(image.Object);
        var target = new CompanyProfileController(Mock.Of<ICompanyProfileService>(), companyService.Object)
        {
            WebImageFactory = factory.Object
        };

        // Act
        target.GetProfileImage(99);

        // Assert
        image.Verify(i => i.Write(null), Times.Once);
    }

Whew! A lot of work, but again, a good learning experience for me, and if I ever need this code again I have it. I also hope it could be useful for someone else with this concern.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM