如何在ASP中使用WebImage对控制器进行单元测试.. Net MVC应用

本文关键字:控制器 单元测试 Net 应用 MVC WebImage ASP | 更新日期: 2023-09-27 18:15:37

我有这个非常简单的方法在MVC控制器:

    public void GetProfileImage(int id)
    {
        var data = _companyService.GetProfileImage(id);
        if (data == null)
            return;
        var image = new WebImage(data).ResizeMaxPreserveTransparency(250, 250);
        image.Write();
    }

有没有人有任何建议,我如何可以测试这个,模拟WebImage,或重构它更可测试?谢谢。

如何在ASP中使用WebImage对控制器进行单元测试.. Net MVC应用

几点:

  1. 方法名以"Get"开头,方法不返回任何东西。
  2. 当你在GetProfileImage内更新图像时,你应该测试这些更新是否正确完成。这是您编写单元测试时要针对的一种情况。
  3. 为了测试方法的行为(例如,图像的最大透明度设置为250),你应该返回图像对象。

我在这上面花了很长时间,但这对我来说是一次很好的学习经历。我是这样做的:

1)创建一个接口,封装我需要的WebImage的方法和属性:

 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)创建一个包装器来实现这个接口,并且是一个实际的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)为工厂创建一个接口,该接口可以被模拟以提供一个模拟的IWebImage,也可以被注入以提供一个实际的WebImageWrapper。

public interface IWebImageFactory
{
    IWebImage Get(byte[] data);
}
这个工厂接口的实际实现,将被Ninject注入到控制器中,看起来像这样:
public class WebImageFactory : IWebImageFactory
{
    public IWebImage Get(byte[] data)
    {
        return new WebImageWrapper(data);
    }
}
最后,我的控制器方法现在看起来像这样:
    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是一个注入的属性,所以我可以提供任何我想要的模拟,这反过来可以提供一个模拟的IWebImage。从这一点开始,创建单元测试是微不足道的。

    [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);
    }

唷!做了很多工作,但对我来说,这是一个很好的学习经验,如果我再次需要这个代码,我就有了。我也希望它能对其他有这种担忧的人有用。