Moq object always returns null - why?
I am trying to get to grips with Moq and using a simple example to figure it out. I am using Google to geocode an address. I have wrapped WebClient so it can be mocked. Here is the code:
public class Position
{
public Position(double latitude, double longitude)
{
Latitude = latitude;
Longitude = longitude;
}
public virtual double Latitude { get; private set; }
public virtual double Longitude { get; private set; }
}
public interface IWebDownloader
{
string Download(string address);
}
public class WebDownloader : IWebDownloader
{
public WebDownloader()
{
WebProxy wp = new WebProxy("proxy", 8080);
wp.Credentials = new NetworkCredential("user", "password", "domain");
_webClient = new WebClient();
_webClient.Proxy = wp;
}
private WebClient _webClient = null;
#region IWebDownloader Members
public string Download(string address)
{
return Encoding.ASCII.GetString(_webClient.DownloadData(address));
}
#endregion
}
public class Geocoder
{
public Position GetPosition(string address, IWebDownloader downloader)
{
string url = string.Format("http://maps.googleapis.com/maps/api/geocode/xml?address={0}&sensor=false",
address);
string xml = downloader.Download(url);
XDocument doc = XDocument.Parse(xml);
var position = from p in doc.Descendants("location")
select new Position(
double.Parse(p.Element("lat").Value),
double.Parse(p.Element("lng").Value)
);
开发者_Go百科return position.First();
}
}
All good so far. Now here is the unit test with Moq:
[TestMethod()]
public void GetPositionTest()
{
Mock<IWebDownloader> mockDownloader = new Mock<IWebDownloader>(MockBehavior.Strict);
const string address = "Brisbane, Australia";
mockDownloader.Setup(w => w.Download(address)).Returns(Resource1.addressXml);
IWebDownloader mockObject = mockDownloader.Object;
Geocoder geocoder = new Geocoder();
Position position = geocoder.GetPosition(address, mockObject);
Assert.AreEqual(position.Latitude , -27.3611890);
Assert.AreEqual(position.Longitude, 152.9831570);
}
The return value is in a resource file and is the XML output from Google. Now when I run the unit test I get the exception:
All invocations on the mock must have a corresponding setup..
If I turn off strict mode, then the mock object returns null. If I change the setup to:
mockDownloader.Setup(w => w.Download(It.IsAny<string>())).Returns(Resource1.addressXml);
then the test runs fine. But I don't want to test for any string, I want to test for this specific address.
Please put me out of my misery and tell my where I am going wrong.
As far as I can tell, you're having your mock return a specific value when it receives the string "Brisbane, Australia", but you're passing it the value http://maps.googleapis.com/maps/api/geocode/xml?address=Brisbane,%20Australia&sensor=false
(or however it ends up getting formatted).
Try something like this in your test code:
…
const string address = "Brisbane, Australia";
const string url = string.Format("http://maps.googleapis.com/maps/api/geocode/xml?address={0}&sensor=false", address);
mockDownloader.Setup(w => w.Download(url)).Returns(Resource1.addressXml);
…
精彩评论