Правильно пишем тест-кейсы. памятка начинающему специалисту по тестированию
Когда смотришь на специалистов по тестированию, которые пишут тест-кейсы, то понимаешь, что многие из них даже не имеют представления как это правильно делается. Я не буду приводить множество примеров, которые показывают вопиющие ошибки, а постараюсь озвучить основные принципы того, как надо писать тест-кейсы.
Для начинающих поясним, что такое тест-кейс озвучив определение из глоссария терминов ISTQB:
Тест-кейс — набор входных значений, предусловий выполнения, ожидаемых результатов и постусловий выполнения, разработанный для определённой цели или тестового условия, таких как выполнения определённого пути программы или же для проверки соответствия определённому требованию.
Определение тест-кейса языком обывателя:
Тест-кейс — это чёткое описание действий, которые необходимо выполнить, для того чтобы проверить работу программы (поля для ввода, кнопки и т.д.). Данное описание содержит: действия, которые надо выполнить до начала проверки — предусловия; действия, которые надо выполнить для проверки — шаги; описание того, что должно произойти, после выполнения действий для проверки — ожидаемый результат.
Надеюсь, теперь многим стало понятно, что такое тест-кейс. Теперь перейдём к правилам написания тест-кейсов, которые вырабатывались не один год и показывают свою эффективность до сих пор.
Обязательные атрибуты для заполнения
- Номер тест-кейса — уникальный идентификатор тест-кейса (такие системы как TestRail, TestLink и подобные автоматически присваивают тест-кейсам уникальные номера). Если у вас тысячи тест-кейсов, то при общении с коллегами, вам будет удобнее сообщить номер тест-кейса ссылаясь на него, а не пытаться словами рассказать, где и как найти определённый тест-кейс.
- Заголовок — краткое, понятное и ёмкое описание сути проверки.
- Предусловия — описание действий, которые необходимо предварительно выполнить или учесть, и которые не имеют прямого отношения к проверке.
- Шаги проверки — описание последовательности действий, которые необходимо выполнить для проверки.
- Ожидаемый результат — проверка, которая устанавливает, что мы ожидаем получить, после выполнения определённых действий в соответствующем шаге.
В зависимости от специфики компании могут присутствовать дополнительные атрибуты для заполнения: приоритет, функциональный блок, программа, ссылка на требование, номер требования и т.д.
Правила написания тест-кейсов
#1 madboy4ik
Хотелось бы узнать, а какие ещё сценарии, можно придумать для тестирование Login формы на рисунке
кроме таких что первыми идут в голову:
#2 leshal
Хотелось бы узнать, а какие ещё сценарии, можно придумать для тестирование Login формы на рисунке
кроме таких что первыми идут в голову:
#5 clauster
- ФИО: Худобородов Валерий
- Город: Espoo
Что будет если поля пустые (оба или одно из них)?
#6 leshal
.
А вообщем спасибо =) некоторые мысли в голову пришли
Вот еще на подумать.
#7 madboy4ik
Что будет если поля пустые (оба или одно из них)?
#8 clauster
- ФИО: Худобородов Валерий
- Город: Espoo
Был бы я тоже гуру, я б тоже посчитал такой пост странным. Я думал что эта тема с бородой и 100% должна была б быть в этом, но к сожалению я не нашёл.
Я гуглил по ‘тестирование Login form’, но в очередной раз убедился что по таким вопросам лучше искать в англоязычных сайтах.
Я понимаю что случаев можно придумать очень много, но не будет же QA целый день тестировать именно login форму
Источник
Cypress пишем первые тесты на авторизацию
Хотел бы поделится небольшим наблюдением о том как можно начать писать тесты на cypress
Установим cypress в devDependency
npm install cypress --save-dev
или yarn
yarn add cypress --dev
cypress open — команда запускает cypress test runner
О структуре cypress
В самом корне проекта появляется папка cypress. Важно заметить что по умолчанию cypress смотрит на ваше приложение в localhost так что оно должно быть запущено команда: npm start или yarn start. Как только запускаете команду cypress open — впервые в корне проекта создаются следующие папки
fixture — чаще всего тут хранят моки для тестов (json/ts/js файлы) используются при cy.fixture() но после 6 версии cy.intercept() принимает как аргумент мок файл
cy.intercept('http://example.com/widgets',{ fixture:'widgets.json'})
Integration — По умолчанию все тесты находятся в папке
plugins — тут можно разширять поведения сайпреса добавляя модули по умолчаню включает в себя cypress / plugins / index.js
support – тут пишем все что можно переиспользовать
Первый тест
describe(‘Test describe’, () => {
it(‘should visit login page’, () => {
cy.visit(‘ http://localhost:4200/')
})
})
как видно тут мы прописываем путь к нашему приложению но так как при первом запуске создается еще и файл cypress.json можно упростить запись и по умолчанию прописать baseUrl в конфиге (О всех возможностях можно посмотерть https://docs.cypress.io/guides/references/configuration.html#Global
// cypress.json
{
“baseUrl”: “http://localhost:4200"
}
Тепреь можно переписать тест
describe('Test describe', () => {
it('should visit login page', () => {
cy.visit('/login')
cy.getEl('register').click()
cy.url().should('include', '/register')
})
})
В тесте мы кликаем на register и проверяем что url есть /register.
Использование data-cy
Скорее всего вас заинтересовала команда
cy.getEl(‘register’).click()
Давайте посмотри что это, в cypresssupportcommands.js я написал небольшую функцию которая возвращает елемент по data-cy (атрибут с html)
Cypress.Commands.add('getEl', name => cy.get(`[data-cy="${name}"]`))
Далее в файле src/app/login/login.component.html. Добавил data-cy=”register” — теперь елемент найти проще простого. Давайте созданим тест на регистрацию, создадим новый файл user.spec.js
describe('auth', () => {
it('fill all the gaps', () => {
cy.visit('/register')
cy.getEl('firstName').type('Nikolay');
cy.getEl('lastName').type('Kozub');
cy.getEl('username').type('mk');
cy.getEl('password').type('qwerty');
})
})
тут так же используем data-cy которые проставляем в файле src/app/register/register.component.html.Проставлять data-cy иногда кажется избыточно но довольно часто именно они не изменяются и являются очнь стабильными
Далее давайте проверим что регистрация рабоатет, допишем тест
describe('auth', () => {
it('fill all the gaps', () => {
cy.visit('/register')
cy.getEl('firstName').type('Nikolay');
cy.getEl('lastName').type('Kozub');
cy.getEl('userName').type('mk');
cy.getEl('password').type('qwerty');
cy.getEl('register').click()cy.getEl('loader').should('be.visible')
cy.getEl('loader').should('not.exist')
cy.url().should('include', '/login');
cy.getEl('alert').should('contains.class', 'alert-success');
cy.getEl('alert').should('contain', 'successful');
})
})
Первое что бы хотелось сделать это вынести все data-cy в отдельный файл давайте это и сделаем. Создадим файл locators.js в cypress/support/ вынесем туда все переменные
export const user = {
name: 'firstName',
lastName: 'lastName',
userName: 'username',
pass: 'password',
regBtn: 'register',
loader: 'loader'
}export const alertTab = {
alert: 'alert'
}
Тепрерь поменяем сам тест
import {alertTab, user} from "../support/locators";describe('User', () => {
it('fill oll the gaps', () => {
cy.visit('/register')
cy.getEl(user.name).type('Nikolay');
cy.getEl(user.lastName).type('Kozub');
cy.getEl(user.userName).type('mk');
cy.getEl(user.pass).type('qwerty');
cy.getEl(user.regBtn).click()
cy.getEl(user.loader).should('be.visible')
cy.getEl(user.loader).should('not.exist')
cy.url().should('include', '/login');
cy.getEl(alertTab.alert).should('contains.class', 'alert-success');
cy.getEl(alertTab.alert).should('contain', 'successful');
})
далее давайте попробуем упростить и удалить часть дублирующего кода
import {alertTab, user, authLocators} from "../support/locators";describe('User', () => {
const {loader, regBtn} = authLocators
const {alert} = alertTab
it('fill all the gaps', () => {
cy.visit('/register')
Object.values(user).forEach(el => cy.getEl(el.key).type(el.value))
cy.getEl(regBtn).click()
cy.getEl(loader).should('be.visible')
cy.getEl(loader).should('not.exist')
cy.url().should('include', '/login');
cy.getEl(alert).should('contains.class', 'alert-success');
cy.getEl(alert).should('contain', 'successful');
})
})
Сохранение данных о пользователе
Теперь давайте посмотрим как нам сохранить данные о пользователе для тестов после регистрации. Для этого добавим в cypress.json username, password
{
"baseUrl": "http://localhost:4200",
"username": "mk",
"password": "qwerty"
}
После чего можно заметить что у нас в двух местах хранятся одни и те же данные, давайте сделаем только ‘один источник правды’ изменим locators.js
export const user = {
firstName: 'Nikolay',
lastName: 'Kozub',
username: Cypress.config('username'),
password: Cypress.config('password'),
}
Cypress.config(name), — берет данные с cypress.json
Авторизация
После регистрации давайте проверим что логин так же работает корректно (ранее мы записали данные о пользователе в cypress.json) — конечно мы можем каждый раз регистрировать нового пользоватяля и проходить им авторизацию но это довольно избыточно.
Наше приложение берет данные о пользователе с localStorage посмотреть логику работы можно в src/app/_helpers/fake-backend.ts
Первое что можно сделать пройти авторизацию и посмотреть что происходит в dev tools, давайте так и сделаем.
Тут мы видим все данные которые нам нужны. Теперь мы можем или копировать все эти данные и сохранить как user.json в firtures папке или же немного их изменить и сделать боле хитрыми. Первое что сделаем, напишем простую функцию которая будет записывать данные в localStorage, назовем ее ‘setItem’ открываем cypress/support/commands.js
Cypress.Commands.add('setItem', (keyName, data) => localStorage.setItem(keyName,
JSON.stringify(data),
)
)
Второе пишем небольшую функцию которая будет возвращать массив обьектов.Создадим user.js файл в cypress/fixtures/user.js
export const loginUserData = (firstName, lastName, password, username,idUser = 1) => ([
{
firstName,
lastName,
username,
password,
"id": idUser
}
])
Далее в файле src/app/login/login.component.html проставляем наши data-cy атрибуты:
<input type="text" formControlName="username" data-cy="loginName" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.username.errors }" />
Атрибут на password:
<input type=”password” data-cy=”loginPass” formControlName=”password” class=”form-control” [ngClass]=”{ ‘is-invalid’: submitted && f.password.errors }” />
Атрибут на login:
<button [disabled]="loading" class="btn btn-primary" data-cy="login">Login</button>
src/app/home/home.component.html
<h1 data-cy="userName">Hi {{currentUser.firstName}}!</h1>
Добавим в locators.js новое поле loginBnt, loginName, loginPass
export const authLocators = {
regBtn: 'register',
loader: 'loader',
loginBtn: 'login',
loginName: 'loginName',
loginPass: 'loginPass'
}
export const homePage = {
userName: 'userName'
}
После этого давайте напишем тест на авторизацию, создадим login.spec.js в cypress/integration
import { authLocators, user, homePage } from '../support/locators'
import { loginUserData } from '../fixtures/user'const { name, lastName, userName, pass } = userdescribe('login', () => {before(() => {
cy.setItem('users', loginUserData(name.value,lastName.value,userName.value, pass.value))
cy.visit('/login')
})it('should login user page', () => {
cy.getEl(authLocators.loginName).type(Cypress.config('username'))
cy.getEl(authLocators.loginPass).type(Cypress.config('password'))
cy.getEl(authLocators.loginBtn).click()
cy.getEl(homePage.userName).should('contain.text', name.value)
})
})
Запросы на сервер
Далее давайте посмотрим как cypress работает с запросими на сервер. Что бы дождаться ответа от сервера используют такой подход
cy.intercept('http://example.com/settings').as(‘alias’)
cy.wait(‘@alias’)
.as(‘alias’) — псевдоним с помощью которого можно получить асинхронный запрос
cy.wait(‘@alias’) — ожидает ответ и возвращает promise
Давайте проверим что происходит при авторизации и добавим проверку response при загрузке данных, заодно посмотрим как это работает
import { authLocators, user, homePage } from '../support/locators'
import { loginUserData } from '../fixtures/user'const { name, lastName, userName, pass } = user
describe('login', () => {
before(() => {
cy.setItem('users', loginUserData(name.value, lastName.value, userName.value, pass.value))
cy.visit('/login')
cy.getEl(authLocators.loginName).type(Cypress.config('username'))
cy.getEl(authLocators.loginPass).type(Cypress.config('password'))
cy.intercept('GET', '**/posts').as('alias')
cy.getEl(authLocators.loginBtn).click()
})
it('should login user page', () => {
cy.wait('@alias').then(req => {
const { body } = req.response
const firstTenItems = body.splice(0, 10).map(el => el.title)
firstTenItems.forEach((el, idx) =>
cy.getEl(homePage.listItem)
.eq(idx)
.then(element => expect(element.text()).contains(el)),
)
cy.getEl(homePage.userName).should('contain.text', name.value)
})
})
})
Как видим у нас получидся довольно таки большой тест в котором приходиться еще и проходить авторизацию в ui. Зачастую тест на авторизацию напишут отдельно, а авторизацию делают с помощью запроса к беку без ui. Давайте рассмотрим один из примеров как бы это выглядело для нашего приложения.
Авторизация без ui формы:
Переходим к cypress/support/commands.js и пишем команду
Cypress.Commands.add('login', () => {
cy.request({
method: 'POST',
url: '/login',
body: {
username: Cypress.config('username'),
password: Cypress.config('password')
}
}).then((response) => {
localStorage.setItem('token', response.body);
});
});
Теперь эту команду можно использовать в тестах перед авторизацией, но так как у нас нет api добавлять ее не будем. Довольно много проектов используют такой принцип авторизации, так что возможно это будет полезно. Сам проект можно посмотреть тут https://github.com/NikolayKozub/angular-coverage-cypress
Oauth 2.0: сценарий для веб-серверных приложений
В целом, OAuth 2.0 Authorization code flow включает в себя:
- Процесс авторизации начинается, когда ваше приложение перенаправляет браузер на URL страницы авторизации стороннего сервиса. URL-адрес включает параметры запроса, которые указывают тип запрашиваемого доступа, id клиента, функциональность, права на которую запрашиваются (scope), адрес, на который будет перенаправлен пользователь после проверки (redirect url).
- Сторонний сервис API обрабатывает аутентификацию пользователя, выбор сессии и согласие пользователя (сonsent dialog).
- Результат — код авторизации, который приложение может обменять на access token и refresh token.
Наиболее проблемная для автоматизации часть сценария — второй пункт, поскольку реализация может варьироваться в зависимости от сервиса, и мы не можем контролировать, каким способом сервис обрабатывает аутентификацию пользователя. Кроме того, здесь требуются действия пользователя.
Testconfig
Что нам нужно сделать. Нам нужно:
Начнем. Для того чтобы взять Web.Config – нам нужно скопировать его в свою папку. Назовем её Sandbox. Теперь скопируем, поставим на pre-build Event в Project Properties:
xcopy $(SolutionDir)LessonProjectWeb.config $(ProjectDir)Sandbox /y
При каждом запуске билда мы копируем Web.config (и, если надо, то перезаписываем) к себе в Sandbox.Создадим TestConfig.cs и в конструктор будем передавать наш файл (/Tools/TestConfig.cs):
Генерация данных
Кроме всего прочего, мы можем и не удалять базу данных после пробегов теста. (переписать)Я добавлю GenerateData проект в папку Test, но подробно рассматривать мы его не будем, просто чтобы был. Он достаточно тривиальный. Суть его – есть некоторые наименования, и мы используем их для генерации. Например, для генерации фамилии используются фамилии американских президентов (зная их, мы сразу отличаем их от других фамилий, которые скорее будут реальными).
Это также в будущем позволяет избежать «эффекта рыбы», когда в шаблоне тестовые данные были одной определенной, но не максимальной длины и шаблон выглядел прилично, но при использовании реальных данных всё поехало.Создадим 100 пользователей и потом посмотрим на них:
Замена ui-авторизации на api для автотестов
Один из важнейших вызовов в автоматизированном тестировании, по моему мнению, – это обеспечить его высокую надёжность. В решении проблемы улучшения показателей надёжности тестирования, хорошо себя зарекомендовал подход использования API интерфейса вместо UI. В данной статье мы подробно разберём простой механизм замены UI авторизации на API.
Существует большое количество видов аутентификации – Basic, Digest, Form, OAuth 1 и OAuth 2. В качестве примера я предлагаю рассмотреть одну из простейших, а именно – Form. Основная задача статьи – это показать подход внедрения API авторизации для UI тестов. Тесты и имплементацию будем писать на Java. Из инструментов будем использовать Chrome DevTools.
В качестве объектов тестирования используем Kanboard та DVWA. Это open source продукты с открытой лицензией, которые достаточно легко развернуть локально. По ссылкам можно прочитать больше про данные продукты и при необходимости ознакомиться с инструкциями из развёртки.
Проект создадим с помощью maven и добавим testng, selenide, rest-assured, json-path, jsoup, maven-compiler-plugin та maven-surefire-plugin.
Логинимся в Kanboard с открытой вкладкой Network Chrome DevTools.
Проанализировав DevTools, мы можем узнать алгоритм авторизации. В данном случае, для авторизации выполняются два запроса: GET с двумя query параметрами и POST з парой логин/пароль и csrf токеном. Первый запрос необходим для того, чтобы получить KB_SID cookie. Второй – для KB_RM cookie. Установив оба этих значения в WebDriver, мы получаем доступ к главной странице.
Первый запрос в RestAssured будет выглядеть следующим образом
Response response01 = given()
.queryParam("controller", "AuthController")
.queryParam("action", "login")
.when()
.get(BASE_URL);
Из него мы получаем KB_SID cookie
String cookieKBSID = response01.getCookie("KB_SID");
CSRF-токен находится в доме HTML-страницы, которую мы можем увидеть в теле респонса.
Получить его нам поможет библиотека jsoup, которая позволяет разделять документ на элементы. Поиск производится подобным же образом, как и Web елементи.
String cSRFToken = Jsoup.parseBodyFragment(response01.body().asString())
.getElementsByAttributeValue("name", "csrf_token").attr("value");
Второй запрос в RestAssured будет выглядеть следующим образом:
Response response02 = RestAssured
.given()
.config(RestAssured.config()
.encoderConfig(EncoderConfig.encoderConfig()
.encodeContentTypeAs("x-www-form-urlencoded", ContentType.URLENC)))
.contentType("application/x-www-form-urlencoded; charset=UTF-8")
.formParam("remember_me", "1")
.formParam("username", "admin")
.formParam("password", "admin")
.formParam("csrf_token", cSRFToken)
.queryParam("controller", "AuthController")
.queryParam("action", "check")
.cookie("KB_SID", cookieKBSID)
.when()
.post(BASE_URL);
На этом этапе стоит обратить внимание на то, что запрос необходимо правильно заенкодить (encoderConfig, encodeContentTypeAs).
Из него мы получаем KB_RM cookie.
String setCookieHeaderValue = response02.header("Set-Cookie");
Теперь, когда мы получили все необходимые элементы, нам остаётся только открыть нужную страницу з заполненными полями cookie.
WebDriverRunner.getWebDriver()
.manage().addCookie(new Cookie("KB_SID", cookieKBSID));
WebDriverRunner.getWebDriver()
.manage().addCookie(new Cookie("KB_RM", cookieKBRM));
Selenide.open(url);
Для DVWA все происходит аналогично, только токен будет иметь другое имя.
Безусловно, для других видов аутентификации количество запросов и их сложность будет отличаться. Однако, базовый принцип остаётся неизменным – проанализировать полученный алгоритм и воспроизвести его с помощью RestAssured.
Благодарю за внимание и надеюсь, что эта статья была полезной для Вас.
Интегрированное тестирование
Идея будет совершенно безумной, мы будем использовать и проверять уже существующий код в SqlRepository. Для этого мы через Web.config находим базу (она должна располагаться локально), дублировать ее, подключаться к дубликату БД, проходить тесты и в конце, удалять дубликат БД.
Создаем проект LessonProject.IntegrationTest в папке Test.
Добавляем Ninject, Moq и NUnit:
Install-Package Ninject
Install-Package Moq
Install-Package NUnit
Так же создаем папку Sandbox и в Setup наследуем UnitTestSetupFixture (/Setup/IntegrationTestSetupFixture.cs) и функцию по копированию БД:
[SetUpFixture]
public class IntegrationTestSetupFixture : UnitTestSetupFixture
{
public class FileListRestore
{
public string LogicalName { get; set; }
public string Type { get; set; }
}
protected static string NameDb = "LessonProject";
protected static string TestDbName;
private void CopyDb(StandardKernel kernel, out FileInfo sandboxFile, out string connectionString)
{
var config = kernel.Get<IConfig>();
var db = new DataContext(config.ConnectionStrings("ConnectionString"));
TestDbName = string.Format("{0}_{1}", NameDb, DateTime.Now.ToString("yyyyMMdd_HHmmss"));
Console.WriteLine("Create DB = " TestDbName);
sandboxFile = new FileInfo(string.Format("{0}\{1}.bak", Sandbox, TestDbName));
var sandboxDir = new DirectoryInfo(Sandbox);
//backupFile
var textBackUp = string.Format(@"-- Backup the database
BACKUP DATABASE [{0}]
TO DISK = '{1}'
WITH COPY_ONLY",
NameDb, sandboxFile.FullName);
db.ExecuteCommand(textBackUp);
var restoreFileList = string.Format("RESTORE FILELISTONLY FROM DISK = '{0}'", sandboxFile.FullName);
var fileListRestores = db.ExecuteQuery<FileListRestore>(restoreFileList).ToList();
var logicalDbName = fileListRestores.FirstOrDefault(p => p.Type == "D");
var logicalLogDbName = fileListRestores.FirstOrDefault(p => p.Type == "L");
var restoreDb = string.Format("RESTORE DATABASE [{0}] FROM DISK = '{1}' WITH FILE = 1, MOVE N'{2}' TO N'{4}\{0}.mdf', MOVE N'{3}' TO N'{4}\{0}.ldf', NOUNLOAD, STATS = 10", TestDbName, sandboxFile.FullName, logicalDbName.LogicalName, logicalLogDbName.LogicalName, sandboxDir.FullName);
db.ExecuteCommand(restoreDb);
connectionString = config.ConnectionStrings("ConnectionString").Replace(NameDb, TestDbName);
}
}
По порядку: В строках
var config = kernel.Get<IConfig>();
var db = new DataContext(config.ConnectionStrings("ConnectionString"));
— получаем подключение к БД.
TestDbName = string.Format("{0}_{1}", NameDb, DateTime.Now.ToString("yyyyMMdd_HHmmss"));
Создаем наименование тестовой БД.
//backupFile
var textBackUp = string.Format(@"-- Backup the database
BACKUP DATABASE [{0}]
TO DISK = '{1}'
WITH COPY_ONLY",
NameDb, sandboxFile.FullName);
db.ExecuteCommand(textBackUp);
— выполняем бекап БД в папку Sandbox.
var restoreFileList = string.Format("RESTORE FILELISTONLY FROM DISK = '{0}'", sandboxFile.FullName);
var fileListRestores = db.ExecuteQuery<FileListRestore>(restoreFileList).ToList();
var logicalDbName = fileListRestores.FirstOrDefault(p => p.Type == "D");
var logicalLogDbName = fileListRestores.FirstOrDefault(p => p.Type == "L");
— получаем логическое имя БД и файла логов, используя приведение к классу FIleListRestore.
var restoreDb = string.Format("RESTORE DATABASE [{0}] FROM DISK = '{1}' WITH FILE = 1, MOVE N'{2}' TO N'{4}\{0}.mdf', MOVE N'{3}' TO N'{4}\{0}.ldf', NOUNLOAD, STATS = 10", TestDbName, sandboxFile.FullName, logicalDbName.LogicalName, logicalLogDbName.LogicalName, sandboxDir.FullName);
db.ExecuteCommand(restoreDb);
— восстанавливаем БД под другим именем (TestDbName)
connectionString = config.ConnectionStrings("ConnectionString").Replace(NameDb, TestDbName);
— меняем connectionString.
И теперь можем спокойно проинициализировать IRepository к SqlRepository:
protected override void InitRepository(StandardKernel kernel)
{
FileInfo sandboxFile;
string connectionString;
CopyDb(kernel, out sandboxFile, out connectionString);
kernel.Bind<webTemplateDbDataContext>().ToMethod(c => new webTemplateDbDataContext(connectionString));
kernel.Bind<IRepository>().To<SqlRepository>().InTransientScope();
sandboxFile.Delete();
}
Итак, у нас есть sandboxFile – это файл бекапа, и connectionString – это новая строка подключения (к дубликату БД). Мы копируем БД, связываем именно с SqlRepository, но базу подсовываем не основную. И с ней можно делать всё что угодно. Файл бекапа базы в конце удаляем.И дописываем уже удаление тестовой БД, после прогона всех тестов:
Как правильно создавать тест-кейсы для формы регистрации?
Например, есть форма регистрации с множеством полей. Если не заполнить (или заполнить невалидными данными) все поля и нажать [Отправить], то под каждым полем высветится ошибка, если заполнить все поля валидными данными кроме одного, то только под одним полем высветится ошибка.
Как правильней? 1) Проверить, что все ошибки высветились сразу заполнив все поля невалидными данными или оставив их пустыми? (т.е. будет максимум 2 тест-кейса) 2) Проверить, что появилась ошибка под полем n, после заполнения всех полей кроме поля n валидными данными. Повторить n раз для каждого поля. (Множество тест-кейсов)
- Вопрос задан более двух лет назад
- 11581 просмотр
Если форма заполнена не полностью, то кнопка отправить должна быть неактивна. Если форма заполнена невалидными данными и/или неполностью — кнопка «Отправить» должна быть неактивна и неверно заполненые поля должны показывать подсказку. Для каждого поля нужно проверять, что разные ошибочные варианты ввода в это поле распознаются.
Переполнение поля тоже. Если есть необязательные поля, нужно проверить, что их заполнение, незаполнение или неверное заполнение не влияет на результат. Если есть кнопки переключатели (radio buttons) можно проверить выставляется ли значение по умолчанию если должно или не выставляется если не должно. Бывает что выставляется хотя не должно.
Кроме этого навигацию по полям табуляцией можно проверить. Можно проверить, что при перезагрузке страницы введенные в формуляр данные не сбрасываются, если они не должны сбрасываться. Если поля поддерживают автозаполнение можно проверить и это. Если формуляр многостраничный — нужно проверить навигацию между страницами, что введенные данные не теряются. Что их можно отредактировать вернувшись назад.
Не думайте о количестве тесткейсов, думайте о том, в чем вы хотите убедиться.
Источник
Способы автоматизации сценария авторизации
Отталкиваясь от требований проекта, мы можем реализовать сценарий авторизации OAuth2.0 двумя способами:
Сценарии для тестирования login формы
- Авторизуйтесь для ответа в теме
Тестируемый компонент: авторизация на сайте
Составить тест-кейсы на тестирование формы авторизации на страничке.
Форма авторизации имеет:
Вывод
https://www.youtube.com/watch?v=dwYE7uLt_j4
Оба подхода имеют свои недостатки и преимущества и могут быть реализованы в рамках автоматизации тестов. Но давайте обозначим условия, при которых мы можем извлечь из каждого подхода максимум преимуществ.