Простые unit-тесты на проверку пароля

191
24 декабря 2018, 01:30

Помогите переделать Unit-тест. На форме AdForm имеется textbox, на который нужно написать два простых unit-теста. На проверку правильности ввода, и не правильности ввода пароля т.е. два отдельных unit-теста.

Код который хочу тестировать:

 public void button5_Click(object sender, EventArgs e)
        {
            if (maskedTextBox4.Text == "qwerty") // вот это тестить хочу
            {
                AdForm adForm = new AdForm(this);
                adForm.Show();
                this.Hide();
            }
        }

Мой корявый наброски Unit-тестов:

[TestMethod()]
public void login()
{
    AdForm n = new AdForm ();
    string rez = n.insCl("qwerty");
    string exp = "Успешно";
    Assert.AreEqual(rez, exp);
}

[TestMethod]
public void login()
{
    adForm  n = new adForm ();
    n.Text(true,"qwerty");
}

[TestMethod()]
public void login()
{
    AdForm test1 = new AdForm ();
    int a = test1.conv("qwerty");
    Assert.AreEqual(a, 0);
}

P.S. Если кто поможет, буду благодарен. Мне бы один правильный вариант Unit-теста на проверку. Дальше сам. Не ругайтесь.

Код формы:

namespace roza
{
    public partial class AuthForm : Form
    {
        public AuthForm()
        {
            InitializeComponent();
        }
            public void button5_Click(object sender, EventArgs e)
            {
                if (maskedTextBox4.Text == "qwerty") // вот это тестить хочу
                {
                    AdForm adForm = new AdForm(this);
                    adForm.Show();
                    this.Hide();
                }
            }
        }
    }
}

Вот так должна выглядеть работа Unit-теста

Тест-->Выполнить-->Все тесты

Answer 1

Допустим, у вас есть сервис для проверки пароля

public class LoginService
{
    public bool Login(string secret)
    {
        return secret == "qwerty";
    }
}

И вы используете его на своей форме

public class LoginForm : Form
{
    LoginService _loginService;
    public LoginForm(LoginService loginService)
    {
        _loginService = loginService;
        var passwordBox = new TextBox();
        var loginButton = new Button() { Text = "Login", Top = 50 };
        loginButton.Click += (sender, args) =>
        {
            var text = passwordBox.Text;
            if (loginService.Login(text))
                MessageBox.Show("Login sucessed");
            else
                MessageBox.Show("Login failed");
        };
        this.Controls.Add(passwordBox);
        this.Controls.Add(loginButton);
    }
}

Создание формы выглядит так:

var service = new LoginService();
var form = new LoginForm(service);
form.ShowDialog();

Результат выглядит так:

Тесты писать надо будет для сервиса, так как только он содержит логику, определяющую, правильный был передан пароль или нет. Пример 2 тестов - позитивный и негативный:

[TestMethod()]
public void login_failed()
{
    var loginService = new LoginService();
    var actual = loginService.Login("wrong password");
    var expected = false;
    Assert.AreEqual(actual, expected);
}

[TestMethod()]
public void login_sucessed()
{
    var loginService = new LoginService();
    var actual = loginService.Login("qwerty");
    var expected = true;
    Assert.AreEqual(actual, expected);
}
Answer 2

Вся проблема в том, что вы не отделили классы UI (ваши формочки) и бизнес-логику.

Это очень стандартная ошибка новичков: фигачить бизнес-логику прямо в buttonN_click.

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

А пока это у вас не будет юнит-тест, это будет что-то ближе к интеграционному тесты, либо юнит-тест, но хрупкий, который зависит и от UI и от фаз луны и от чего-нибудь ещё.

Посмотрите вот мои примеры юнит-тестов: у меня в проекте ни одной формы нет, а тесты есть.

Как вам нужно поступить в вашем случае. У вас есть некий класс формы, вам нужно объявить, что этот класс имеет зависимость от некоторого класса, реализующего интерфейс проверки пароля.

Было:

public partial class AuthForm : Form
{
    public AuthForm()
    {
        InitializeComponent();
    }
    public void button5_Click(object sender, EventArgs e)
    {
        if (maskedTextBox4.Text == "qwerty") // вот это тестить хочу
        {
            AdForm adForm = new AdForm(this);
            adForm.Show();
            this.Hide();
        }
    }
}

Стало:

public partial class AuthForm : Form
{
    public AuthForm(IPasswordCheckerService passwordCheckerService)
    {
        this.PasswordCheckerService = passwordCheckerService;
        InitializeComponent();
    }
    private IPasswordCheckerService PasswordCheckerService { get; set; }
    public void button5_Click(object sender, EventArgs e)
    {
        if (this.PasswordCheckerService.IsPasswordValid(maskedTextBox4.Text)) // вот это тестить хочу
        {
            AdForm adForm = new AdForm(this);
            adForm.Show();
            this.Hide();
        }
    }
}
public interface IPasswordCheckerService 
{
    bool IsPasswordValid(string password)
}

И вот с этим уже можно работать.

Вы можете создать кучу классов, которые реализуют данный интефейс - от простых, которые возвращают всегда true или которые проверяют что пароль равен какой-либо захардкоженной строке до очень сложных, которые лезут в реестр виндовс, базу данных, облако и т.п.

Вот простой пример класса, реализующего интерфейс:

public class SimplePasswordChecker : IPasswordCheckerService
{
    public bool IsPasswordValid(string password)
    {
        return true;
    }
}

А вот простой тест:

[Test]
public void IsPasswordValid_PasswordMatch_ReturnsTrue()
{
    // Arrange
    var checker = new SimplePasswordChecker();
    // Act
    var result = checker.IsPasswordValid("qwerty");
    // Assert
    Assert.IsTrue(result);
}
[Test]
public void IsPasswordValid_PasswordMismatch_ReturnsFalse()
{
    // Arrange
    var checker = new SimplePasswordChecker();
    // Act
    var result = checker.IsPasswordValid("asdf");
    // Assert
    Assert.IsFalse(result);
}

Разумеется, этот тест "не пройдёт". Как и полагается в TDD мы сначала написали красный тест, потом исправляем код класса SimplePasswordChecker на тот, который пройдёт тест.

Получившиеся классы никак не завязаны на то, какой у вас интерфейс - сегодня это winforms, завтра wpf, веб или мобильное приложение. А бизнес-логика остаётся отдельным проектом в решении, которое не имеет никаких зависимостей. Поэтому все эти классы бизнес-логики сразу отселяйте в отдельный проект и начинайте структурировать своё приложение - это и есть архитектура приложения, когда у вас слои разделяют обязанности, а не валят всё в одну кучу.

PS Как передавать зависимость на конструктор - оставляю вам на самостоятельную проработку. В идеале вообще такие вещи делаются при помощи DI.

READ ALSO
Как преобразовать string или datetime.month в int?

Как преобразовать string или datetime.month в int?

Необходимо преобразовать месяц даты в intВходная строка из потока выглядит следующим образом: "12

179
Наследование свойства IsEnabled в TabControl

Наследование свойства IsEnabled в TabControl

Подскажите как решить следующую проблемуЕсть TabControl с несколькими TabItem

167
Не функционирует перемещение Unity 2D

Не функционирует перемещение Unity 2D

Написал скрипт на шарпе, прикрепил его к обьекту игрока, по задумке изображение должно перемещаться по нажатию на стрелку вправо, но ничего...

131