Why does the property I want to mock need to be virtual?

后端 未结 4 571
遥遥无期
遥遥无期 2020-12-01 10:10

I\'m doing some unit testing, and mocking some properties using Moq.

Now, this is a Controller test (ASP.NET MVC 3). My Controllers

相关标签:
4条回答
  • 2020-12-01 10:50

    "So....what i did is the only way?"

    No not the only way - you are much better off implementing an interface and mocking that. Then your actual methods can be virtual or not as you choose.

    0 讨论(0)
  • 2020-12-01 10:58

    Although, all that was said before is true, it's worth to know that the proxy-mocking approach (like the one that moq uses)i s not the only one possible.

    Check http://www.typemock.com/ for a comprehensive, solution, that allows you to mock both sealed classes, non-virtual methods etc. Pretty powerful.

    0 讨论(0)
  • 2020-12-01 11:03

    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.

    0 讨论(0)
  • 2020-12-01 11:07

    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.

    0 讨论(0)
提交回复
热议问题