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:
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. 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.