I'm doing some unit testing, and mocking some properties using Moq.
Now, this is a Controller test (ASP.NET MVC 3). My Controllers derive from an abstract controller, called AbstractController.
This controller has a dependency on the Http Context (in order to do things like theming, domain-specific logic based on HTTP HOST headers, etc).
This is done via a property called WebSiteSettings:
public abstract class AbstractController : Controller { public WebSiteSettings WebSiteSettings { get; private set; } // other code }
Notice the private set - the ctor sets it up. So, i changed it to used an interface, and that's what i've mocked:
public IWebSiteSettings WebSiteSettings { get; private set; }
I then created a "FakeWebSiteSettings", which mocks the Http Context in order for it to read the HTTP headers.
The problem is, when i run the test, i get a NotSupportedException:
Invalid setup on a non-virtual (overridable in VB) member: x => x.WebSiteSettings
Here's the relevant mocking code:
var mockWebSiteSettings = new Mock<FakeWebSiteSettings>(); var mockController = new Mock<MyController>(SomeRepository); mockController.Setup(x => x.WebSiteSettings).Returns(mockWebSiteSettings.Object); _controller = mockController.Object; var httpContextBase = MvcMockHelpers.FakeHttpContext(); httpContextBase.Setup(x => x.Request.ServerVariables).Returns(new NameValueCollection { {"HTTP_HOST","localhost.www.mydomain.com"}, }); _controller.SetFakeControllerContext(httpContextBase.Object);
If i make the WebsiteSettings
property virtual - the test passes.
But i can't understand why i need to do this. I'm not actually overriding the property, i'm simply mocking how it is setup.
Am i missing something, or doing this wrong?
moqUser. SetupAllProperties(); This method will prepare all properties on the mock to be able to record the assigned value, and replay it later (i.e. to act as real property). You can also use SetupProperty() method to set up individual properties to be able to record the passed in value.
Using mock objects allows developers to focus their tests on the behavior of the system under test without worrying about its dependencies. For example, testing a complex algorithm based on multiple objects being in particular states can be clearly expressed using mock objects in place of real objects.
Mocking is a process used in unit testing when the unit being tested has external dependencies. The purpose of mocking is to isolate and focus on the code being tested and not on the behavior or state of external dependencies.
Moq and other similar mocking frameworks can only mock interfaces, abstract methods/properties (on abstract classes) or virtual methods/properties on concrete classes.
This is because it generates a proxy that will implement the interface or create a derived class that overrides those overrideable methods in order to intercept calls.
I've created an interface and wrapper class. e.g.
public interface IWebClient { string DownloadString(string url); } public class WebClient : IWebClient { private readonly System.Net.WebClient _webClient = new System.Net.WebClient(); public string DownloadString(string url) { return _webClient.DownloadString(url); } }
and then in your unit tests just mock out the interface:
var mockWebClient = new Mock<IWebClient>();
Obviously you may need to include more properties / methods. But does the trick.
Another useful trick for other mocking problems, such as modifying the current date time (I always use UTC date time):
public interface IDateTimeUtcNowProvider { DateTime UtcNow { get; } } public class DateTimeUtcNowProvider : IDateTimeUtcNowProvider { public DateTime UtcNow { get { return DateTime.UtcNow; } } }
e.g. if you have a service that runs every x minutes you can just mock out the IDateTimeProvider and return a time that is later to check the service ran again... or whatever.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With