Юнит тест с 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. Это также будет означать, что между вашими объектами лучше разделять проблемы, у вас есть один объект, который вызывает веб-сервис, и один объект, который выполняет вычисления.