Юнит тест с nUnit и nMocks

Немного о проблеме nUnit / nMock / Unit-тестирования:

Я пытаюсь провести модульное тестирование этого класса.

Я создал его, потому что хочу узнать значение, возвращаемое из "getCurrencyRates", чтобы я мог создавать тесты на основе этих данных.

Поэтому я создал макет этого объекта (просто для того, чтобы узнать возвращенные обменные курсы).

... но теперь я также хочу вызвать некоторые другие методы этого класса.

Нужно ли мне:

а) как-то вызвать реальные методы из фиктивного объекта (даже не уверен, что это возможно); б) рефакторинг, чтобы только вызов веб-службы находился в своем собственном объекте, и создать макет этого в) что-то еще?

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

2 ответа

Решение

Ваш CurrencyConverter на данный момент делает две вещи: конвертирует валюты (что хорошо) и вызывает внешнюю службу для получения данных (что плохо). Вы хотите, чтобы у ваших занятий были простые, легко определяемые обязанности. Ваш код будет намного чище, более управляемым и, что важно в этом контексте - более тестируемым.

Рефакторинг вашего метода предоставления данных (getCurrencyRates) к внешнему сервису (классу) и внедрить его в ваш объект конвертера (например, с помощью инжектора конструктора).

Кроме того, почему NMocks? Он больше не разрабатывается (последние обновления, кажется, 4-6 лет назад), можно предположить, что его не так легко использовать, как современные фреймворки, такие как FakeItEasy или Moq.

Вы хотите сделать что-то вроде б). Если вы тестируете объект, вы не хотите издеваться над самим объектом, а над его зависимостями.

Зависимость, которую вы хотите смоделировать, - это вызов веб-службы, поскольку размещение реального вызова веб-службы в тесте nunit нарушит принцип юнит-теста, а также станет кошмаром для реализации.

Создать интерфейс для части, включающей вызов веб-службы

ICurrencyRateService 
{
     CurrencyRateResponse GetCurrencyRates()
}

а затем получить весь веб-сервисный код в объект, который реализует это.

это должно позволить вам проверить ConvertCurrency. Это также будет означать, что между вашими объектами лучше разделять проблемы, у вас есть один объект, который вызывает веб-сервис, и один объект, который выполняет вычисления.

Другие вопросы по тегам