Reputation: 759
I have the following code:
public class Weather
{
public int Temperature { get; set; }
public string Description { get; set; }
}
public class WeatherProvider
{
public virtual Weather GetWeather()
{
var w = new Weather();
var hour = Hour;
if (hour < 5)
{
w.Description = "Sunny";
w.Temperature = 12;
}
else if (hour < 12)
{
w.Description = "Windy";
w.Temperature = 18;
}
else
{
w.Description = "Snow";
w.Temperature = 2;
}
return w;
}
public virtual int Hour
{
get { return DateTime.Now.Hour; }
}
}
var mockWeatherProvider = new Moq.Mock<WeatherProvider>(MockBehavior.Loose);
mockWeatherProvider.SetupGet(x => x.Hour).Returns(2);
var actualWeather = mockWeatherProvider.Object.GetWeather();//This line always returns null? WHY???
mockWeatherProvider.Verify(x=>x.GetWeather());
Can any one explain why the line var actualWeather = mockWeatherProvider.Object.GetWeather() returns null? I actually want the real method to be called. How can I achive this?
Upvotes: 2
Views: 2523
Reputation: 2394
By using loose mocking, you're getting the default value for all your virtual properties and mthods. You want to use CallBase to tell Moq to fail back to the normal implementations.
Try this:
var mockWeatherProvider = new Moq.Mock<WeatherProvider>(MockBehavior.Loose) { CallBase = true };
mockWeatherProvider.SetupGet(x => x.Hour).Returns(2);
Upvotes: 3
Reputation: 15578
You haven't set up a behaviour for the GetWeather()
method. Basically, what you're doing here
var mockWeatherProvider = new Moq.Mock<WeatherProvider>(MockBehavior.Loose);
is creating an empty object that looks like WeatherProvider. You have to tell the mockWeatherProvider
what every method and property you want to use should do for you.
Edit, as I realised what you might actually want
If you're trying to mock what is essentially only half of your class, you're going about your implementation in the wrong way in this particular case. If you want to mock, say, what Hour
returns you could provide that property to the WeatherProvider
through some TimeProvider
implementation or some such that the WeatherProvider
depends on.
var mockedTimeProvider = new Moq.Mock<TimeProvider>(MockBehavior.Loose);
mockedTimeProvider.SetupGet(p => p.Hour).Returns(2);
var weatherProvider = new WeatherProvider(mockedTimeProvider.Object);
var actualWeather = weatherProvider.GetWeather();
Edit, again
Try setting your GetWeather()
as not virtual, and then use stubbing instead of complete mocking to generate your mock. That should keep the method from being overridden with a default returner. Though, this way would mud up your design a bit, and not make things as clear as the above would. Separation of concern, and whatnot. =)
Upvotes: 6
Reputation: 9719
Try
var mockWeatherProvider = new Moq.Mock<WeatherProvider>(MockBehavior.Normal);
Upvotes: 0
Reputation: 5825
Your mock doesn't specify an implementation for the GetWeather call. Since you are operating on the mock object and not your concrete implementation, Moq will return the default value. In this case, the default value in null.
If you want to test the implementation, you should just use the concrete implementation and setup the behavior for Hour on that object. This will allow you to exercise the code you have implemented and verify the behavior.
Upvotes: 1