Автотесты на double не проходят
Добрый день пишу авто тесты на калькулятор можно сказать во многом разобрался, осталось только тесты на деление тут у меня проблема при проверки деление с остатком тест не проходит не знаю почему всегда. Такая ошибка
TestDeleniye(145,87,1.66666666666667d) Источник: UnitTest1.cs строка 147 Длительность: 8,6 с Сообщение: Expected string length 16 but was 18. Strings differ at index 1. Expected: "1,66666666666667" But was: "1.6666666666666667"
[TestCase(25, 5, 5)]
[TestCase(50, 0, "Infinity")]
[TestCase(854, 96, 8.89583333333333)]
[TestCase(50, 15, 3.3333333333333335)]
[TestCase(95, 25, 3.8)]
[TestCase(25, 2, 12.5)]
[TestCase(145, 87, 1.66666666666667)]
[TestCase(524, 325, 1.612307692307692)]
[TestCase(320, 120, 2.666666666666666)]
[TestCase(1254, 9652, 0.1299212598425196)]
[TestCase(15487, 9654, 1.604205510669152)]
public void TestDeleniye(double a, double b, object c)
{
IWebDriver driver;
driver = new ChromeDriver();
driver.Manage().Window.Maximize();
driver.Navigate().GoToUrl("file:///C:/Users/HP/Desktop/Calcul2/index.html");
foreach (char ch in a.ToString())
{
driver.FindElement(By.XPath($"//button[@value='{ch}']")).Click();
}
driver.FindElement(By.XPath("//button[@value='/']")).Click();
foreach (char ch in b.ToString())
{
driver.FindElement(By.XPath($"//button[@value='{ch}']")).Click();
}
driver.FindElement(By.XPath("//button[@value='=']")).Click();
IWebElement flashMessage = driver.FindElement(By.XPath("//Input[@type='text']"));
string actual = flashMessage.GetAttribute("value");
NUnit.Framework.Assert.AreEqual(c.ToString(), actual);
driver.Quit();
}
Ответы (1 шт):
То, о чём говорил вам @Bulson.
Нельзя писать тесты на числа с плавающей запятой сравнивая непосредственно значения:
[TestCase(145, 87, 1.66666666666667)]
public void DivisionTest1(double a, double b, double expected)
{
double actual = a / b;
Assert.AreEqual(expected, actual);
}
Необходимо задать некоторую констранту, точность вычисления (Precision), искать разницу (delta, difference) между ожидаемым (expected) и реальным (actual) значением и проверять что разность не больше чем заданная точность.
Вот такой тест проходит нормально:
public class CalculatorTest
{
private const double Precision = 0.000001;
[TestCase(145, 87, 1.66666666666667)]
public void DivisionTest2(double a, double b, double expected)
{
double actual = a / b;
double difference = Math.Abs(actual - expected);
Assert.LessOrEqual(difference, Precision);
}
}
или:
public class CalculatorTest
{
private const double Precision = 0.000001;
[TestCase(145, 87, 1.66666666666667)]
public void DivisionTest2(double a, double b, double expected)
{
double actual = a / b;
Assert.AreEqual(expected, actual, Precision);
}
}
Ну и обратите внимание, что если у вас точность до шестого знака, то в TestCase нет смысла указывать точность на 10 знаков. Это анекдотично "15,04 грамма с точностью плюс-минус килограмм".
Выбор количества нулей когда вы задаёте точность диктуется техническим заданием на проверяемую операцию. Например, при написании тестов на финансовые операции можно выбрать погрешность "меньше чем копейка" (0,1 копейки), в банках берут погрешность ещё меньше и т.п.
Могу ещё дать пару советов по поводу чистоты кода. Код слишком длинный и содержит очень много подробностей как конкретно вы получаете свой реальный результат.
Рекомендую вам вынести всю эту логику хромдрайвера в отдельный метод в базовом классе и в тестах вам достаточно будет только дать одну строку
double actual = Divide(a, b);
Вы же будете писать не один и не два теста, вы постоянно повторяете однообразный код, а это прямой путь к тому, что а) читать сложно и понять непросто б) больше способов запутаться и ошибиться.
Вот скажите, вам же проще будет читать такой тест:
public void DivisionTest(double a, double b, double expected)
{
ClickNumber(a);
ClickDivideOperation();
ClickNumber(b);
ClickEnter();
var actual = GetResults();
Assert.AreEqual(expected, actual, Precision);
}
где в базовый класс вы поместите определения методов:
protected void ClickNumber(double number)
{
foreach (char ch in number.ToString())
{
Driver.FindElement(By.XPath($"//button[@value='{ch}']")).Click();
}
}
protected void ClickDivideOperation()
{
Driver.FindElement(By.XPath("//button[@value='/']")).Click();
}
protected void ClickEnter()
{
Driver.FindElement(By.XPath("//button[@value='=']")).Click();
}
чем постоянно переписывать однотипное driver.FindElement(By. Программист должен стараться писать переиспользуемый код, а не копипасту.
И код методов можно ещё больше упростить, если выделить метод кликающий конкретную кнопку:
protected void ClickNumber(double number)
{
foreach (char ch in number.ToString())
{
ClickButton(ch);
}
}
protected void ClickDivideOperation()
{
ClickButton('/');
}
protected void ClickEnter()
{
ClickButton('=');
}
private void ClickButton(char ch)
{
Driver.FindElement(By.XPath($"//button[@value='{ch}']")).Click();
}
Так потихоньку небольшим рефакторингом (используя паттерн "строитель") можно придти к классическим AAA-тестам:
public void DivisionTest(double a, double b, double expected)
{
// Arrange
var calculator = new Calculator();
// Act
var actual = calculator.ClickNumber(a)
.ClickDivideOperation()
.ClickNumber(b)
.ClickEnter()
.GetResults();
// Assert
Assert.AreEqual(expected, actual, Precision);
}
Второй момент: не сравнивайте строки, здесь много тонких моментов, связанных с отличиями в культуре (точка/запятая в качестве разделителя целой и дробной части, форматирование тысяч и т.п.), а также разницей в регистре букв (если бы вы писали калькулятор 16ричной системы - было бы ещё больнее).
Язык вам предоставляет средства по строгой типизации, поэтому не используйте строки, используйте double. Если где-то из недр хром драйвера приходит строка -- вовремя распарсите её и дальше оперируйте уже только double.
О тестах на деление на ноль. Во-первых, у вас написаны интеграционные тесты, которые тестируют полностью приложение, а не юнит-тесты на бизнес-логику. Обычно в приложении пишутся сначала тесты на бизнес-логику (логику домена приложения), а потом постепенно дополняют интеграционными тестами.
Поэтому вам рекомендуется разделить тесты на два слоя и начать с тестирования бизнес-логики. Деление на ноль выбрасывает исключение, поэтому не стоит писать TestCase - этот тест нужно написать отдельно:
[Test]
public void DivisionByZero_ThrowsExection()
{
Assert.Throws<DivideByZeroException>(() => Division(42, 0));
}
(И вообще, это деление int на 0 даёт такое исключение, если у вас double то просто будет бесконечно большое число, используйте константу double.MaxValue)
И уже во вторую очередь стоит думать как отлавливать такие исключения из кода сайта в интеграционных тестах.