【问题标题】:Moq object always returns null - why?Moq 对象总是返回 null - 为什么?
【发布时间】:2011-09-27 20:36:42
【问题描述】:

我正在尝试掌握起订量并使用一个简单的示例来解决这个问题。我正在使用 Google 对地址进行地理编码。我已经包装了 WebClient,所以它可以被嘲笑。代码如下:

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

        return position.First();
    }
}

到目前为止一切顺利。现在这里是 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);
    }

返回值位于资源文件中,是 Google 的 XML 输出。现在,当我运行单元测试时,我得到了异常:

mock 上的所有调用都必须有相应的设置..

如果我关闭严格模式,则模拟对象返回 null。如果我将设置更改为:

mockDownloader.Setup(w => w.Download(It.IsAny<string>())).Returns(Resource1.addressXml);

然后测试运行良好。但是我不想测试任何字符串,我想测试这个特定的地址。

请让我摆脱痛苦,告诉我哪里出错了。

【问题讨论】:

    标签: unit-testing moq


    【解决方案1】:

    据我所知,当你的模拟接收到字符串“澳大利亚布里斯班”时,它会返回一个特定的值,但你传递给它的是值 http://maps.googleapis.com/maps/api/geocode/xml?address=Brisbane,%20Australia&amp;sensor=false(或者它最终会被格式化)。

    在您的测试代码中尝试这样的事情:

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

    【讨论】:

    • Arrggggggghhh,你是对的。不敢相信我没有发现。我混淆了“地址”这个词的含义。非常感谢。
    • 我建议避免在测试中调用 String.Format 。虽然这是一个简单的示例,但它代表了 SUT 中的确切逻辑。如果该逻辑中存在错误,则测试中存在错误。挖?
    猜你喜欢
    • 1970-01-01
    • 2014-09-12
    • 2019-09-18
    • 2014-09-02
    • 2015-02-27
    • 2021-01-10
    • 1970-01-01
    • 2011-04-16
    • 1970-01-01
    相关资源
    最近更新 更多