3

一个 nUnit / nMock / 单元测试新手问题的位:

我正在尝试对此类进行单元测试。

我创建了一个模拟,因为我想知道从“getCurrencyRates”返回的值,以便我可以基于该数据创建测试。

所以我创建了这个对象的模拟(只是为了能够知道返回的汇率)。

...但现在我也想调用这个类的一些其他方法。

我是不是该:

a) 以某种方式从模拟对象调用真实方法(甚至不确定这是否可能)b) 重构以便只有 Web 服务调用在它自己的对象中并创建一个模拟 c) 其他东西?

public class CurrencyConversion : ICurrencyConversion
{
    public decimal convertCurrency(string fromCurrency, string toCurrency, decimal amount)
    {

        CurrencyRateResponse rates = getCurrencyRates();
        var fromRate = getRate(rates, fromCurrency);
        var toRate = getRate(rates, toCurrency);

        decimal toCurrencyAmount = toRate / fromRate * amount;

        return toCurrencyAmount;
    }


    public int addNumbers(int i, int j)
    {
        return i + j;

    }

    public decimal getRate(CurrencyRateResponse rates, string fromCurrency)
    {

        if (rates.rates.ContainsKey(fromCurrency))
        {
            return rates.rates[fromCurrency];
        }
        else
        {
            return 0;
        }
    }
    public CurrencyRateResponse getCurrencyRates()
    {
        HttpWebRequest webRequest = GetWebRequest("http://openexchangeerates.org/latest.json");

        HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();
        string jsonResponse = string.Empty;
        using (StreamReader sr = new StreamReader(response.GetResponseStream()))
        {
            jsonResponse = sr.ReadToEnd();
        }

        var serializer = new JavaScriptSerializer();
        CurrencyRateResponse rateResponse = serializer.Deserialize<CurrencyRateResponse>(jsonResponse);

        return rateResponse;

    }
    public HttpWebRequest GetWebRequest(string formattedUri)
    {
        // Create the request’s URI.
        Uri serviceUri = new Uri(formattedUri, UriKind.Absolute);

        // Return the HttpWebRequest.
        return (HttpWebRequest)System.Net.WebRequest.Create(serviceUri);
    }
}
4

2 回答 2

3

CurrencyConverter现在做了两件事:转换货币(这很好)并调用外部服务来获取数据(这很糟糕)。您希望您的课程具有单一、易于定义的职责。然后,您的代码将更加清晰,更易于管理,并且在这种情况下重要的是 - 更可测试。

将您的数据提供方法()重构getCurrencyRates为外部服务(类)并将其注入您的转换器对象(例如通过构造函数注入)。

另外,为什么是 NMocks?它不再积极开发(最近一次更新似乎是4-6 年前),人们可能会认为它不像现代框架那样容易使用,例如FakeItEasyMoq

于 2012-02-15T08:34:03.570 回答
2

你会想做类似b)的事情。如果您正在测试一个对象,您不想模拟对象本身,而是模拟它的依赖项。

您要模拟的依赖项是对 Web 服务的调用,因为将真正的 Web 服务调用放在 nunit 测试中会违反单元测试的内容,并且是实现的噩梦。

为涉及 webservice 调用的部分创建接口

ICurrencyRateService 
{
     CurrencyRateResponse GetCurrencyRates()
}

然后将所有 webservicey 代码放入实现此功能的对象中。

这应该允许您测试 ConvertCurrency。这也意味着您的对象之间有更好的关注点分离,您有一个调用 Web 服务的对象和一个执行计算的对象。

于 2012-02-15T08:21:17.983 回答