开发者

Moq object always returns null - why?

开发者 https://www.devze.com 2023-03-16 21:44 出处:网络
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:

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);
…
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号