简体   繁体   English

使用nUnit和nMocks进行单元测试

[英]Unit test with nUnit and nMocks

Bit of a nUnit / nMock / Unit testing noobie question: 一下nUnit / nMock / Unit测试noobie问题:

I am trying to unit test this class. 我正在尝试对这门课进行单元测试。

I have created a mock of it because I want to know the value returned from "getCurrencyRates", so that I can create tests based on that data. 我创建了一个模拟器,因为我想知道“getCurrencyRates”返回的值,以便我可以根据该数据创建测试。

So I created a mock of this object (just to be able to know the exchange rates returned). 所以我创建了一个这个对象的模拟(只是为了能够知道返回的汇率)。

...but now I also want to call some of the other methods on this class. ...但是现在我也想在这个类上调用一些其他方法。

Should I: 我是不是该:

a) somehow call the real methods from the mock object (not even sure if that's possible) b) refactor so that only the web service call is in it's own object and create a mock of that c) something else? 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);
    }
}

Your CurrencyConverter at the moment does two things : converts currencies (which is good) and calls external service to fetch data (which is bad). 您的CurrencyConverter目前做了两件事 :转换货币(这是好的)并调用外部服务来获取数据(这是不好的)。 You want your classes having single , easy definable responsibilities. 您希望您的课程具有单一 ,易于定义的职责。 Your code will be then much cleaner, more managable and, what's important in this context - more testable. 您的代码将更清晰,更易于管理,并且在这种情况下重要的是 - 更可测试。

Refactor your data providing method ( getCurrencyRates ) to external service (class) and inject it to your converter object (for example via constructor injection ). 将数据提供方法( getCurrencyRates )重构为外部服务(类)并将其注入转换器对象(例如通过构造函数注入 )。

Also, why NMocks? 还有,为什么要NMocks? It's no longer actively developed (last updates seem to be 4-6 years ago ), one might assume it's not as easy to use as modern frameworks, such as FakeItEasy or Moq . 它不再被积极开发(最近的更新似乎是4 - 6年前 ),人们可能会认为它不像现代框架那样容易使用,例如FakeItEasyMoq

you'll want to do something like b). 你会想做像b)这样的事情。 If you're testing an object, you don't want to mock the object itself, but its dependencies. 如果您正在测试对象,则不希望模拟对象本身,而是依赖于它。

The dependency you want to mock out is the call to the web service as putting a real webservice call in a nunit test would violate what a unit test is, as well as being a nightmare to implement. 您要模拟的依赖项是对Web服务的调用,因为在nunit测试中放置真正的Web服务调用会违反单元测试,并且是实现的噩梦。

Create an interface for the part involving the webserice call 为涉及webserice调用的部分创建一个接口

ICurrencyRateService 
{
     CurrencyRateResponse GetCurrencyRates()
}

and then get all the webservicey code into an object which implements this. 然后将所有webservicey代码放入一个实现此目的的对象中。

that should allow you to test ConvertCurrency. 应该允许您测试ConvertCurrency。 It also will mean that there is better seperation of concerns between your objects, you have one object which calls a webservice, and one object that does a calculation. 它还意味着您的对象之间可以更好地分离关注点,您有一个调用Web服务的对象,以及一个执行计算的对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM