07 - Висновки з TDD, погляд початківця - Віталій Зінченко - IT Event 2013 (5)
Буде розглянуто підхід розробки програмного забезпечення та тестів, який дозволить досягти наступних цілей:
- глибокий та детальний аналіз вимог;
- одне розуміння функціональності продукту для усіх членів команди;
- хороша взаємодія між командами розробників та тестувальників;
- високий рівень покриття продукту тестами;
- скорочення часу необхідного для тестування;
Результатом виконання перелічених пунктів стане налагоджений процес розробки продукту, порозуміння між учасниками команди і найголовніше - якісне ПЗ.
Віталій Зінченко
http://itevent.if.ua/lecture/visnovki-z-tdd-poglyad-pochatkivtsya
Проєкт «ІТ.UA: народжені в Україні». Єгор Анчишкін
07 - vysnovky z tdd, pohliad pochatkivtsia - vitalii zinchenko it event 2013 (5)
1. Висновки з TDD
погляд початківця
Трішки лірики про процес
Приклад реалізації тесту
Віталій Зінченко
zinchenko.vitaliy@gmail.com
2. Чому виникло бажання про це розповісти?
Подяки:
• http://xpinjection.com
• Микола Аліменков
• Володимир Цукур
• Einar Ingebrigtsen
• Jasson Huggins
• Simon Steward
3. Робочий процес
розробника
аналіз вимог
виділення неподільних елементів
визначення вхідних параметрів і результату
розробка функціоналу
перевірка
створення тестової версії
виправлення помилок
4. Робочий процес
тестувальника
аналіз вимог
виділення неподільних елементів
визначення вхідних параметрів і результату
розробка тестових сценаріїв
перевірка тестової версії
звітування про помилки
5. Що тут не так?
Давайте вирішувати проблеми, ще до їх появи
ізольований аналіз вимог та їх уточнення
питання - як воно працює?
питання - як воно перевіряється?
Результат:
багато дрібних помилок
уточнення після реалізації
витрачений час
6. Єдина задача - єдина команда
Реалізація пліч-о-пліч:
аналіз і уточнення вимог
виділення функціональних частин
створення макету продукту
реалізація функціоналу
написання і розробка тестів
збереження робочих даних в одному місці
8. Перевірки при такому підході
менше запитань і узгоджень після реалізації
менше помилок-багів
розробник використовує тести в процесі написання
функціоналу
тестувальник займається створенням тестів, а не їх
проходженням
частіші та однакові регресивні перевірки
9. Як це все виглядає:
Unit Test, Visual Studio 2012 + NuGet
WebDriver + Selenium
10. Клас BaseObject
using OpenQA.Selenium;
using Selenium;
Using OpenQA.Selenium.Support.PageObjects;
Using OpenQA.Selenium.Support.UI;
namespace FaceBookTest
{
public class BaseObject
{
public static IWebDriver Driver;
public static DefaultSelenium Selenium;
public static void InitPage<T>(T pageClass) where T : BaseObject
{
PageFactory.InitElements(Driver, pageClass);
}
}
}
11. Клас BaseTest
using Nunit.Framework; using OpenQA.Selenium.Firefox; using OpenQA.Selenium.IE;
using OpenQA.Selenium.Chrome; using Selenium;
namespace FaceBookTest
{ public class BaseTest : BaseObject
{
[TestFixtureSetUp]
public void beforeClass(){
Driver = new FirefoxDriver();
//for IE Driver = new InternetExplorerDriver(@"<DOWNLOAD AND SPECIGY PATH
//TO IEDERIVERSERVER HERE(//code.google.com/p/selenium)>");
Selenium = new WebDriverBackedSelenium(Driver, TestTools.homePage);
Selenium.Start()
}
[SetUp]
public void beforeTest(){
Driver.Navigate().GoToUrl(TestTools.homePage);
}
[TestFixtureTearDown]
public void afterClass(){
Driver.Close();
Selenium.Close();
} } }
12. Клас TestTools
using NUnit.Framework;
namespace FaceBookTest
{ class TestTools : BaseObject
{
public static string homePage = "http://www.facebook.com";
private const int DEFAULT_TIMEOUT = 60;
public static void WaitingForElement(string locator, int timeOut =
DEFAULT_TIMEOUT) {
for (int i = 0; i < timeOut; i++){
if (Selenium.IsElementPresent(locator)){
return;
}
else{
System.Threading.Thread.Sleep(1000);
}
}
Assert.Fail("Element with '" + locator + "' not found");
} } }
13. Елементи на Login-сторінці
public class LoginPage : BaseObject
public const string USER_NAME_FIELD = "//input[@id='email']";
public const string PASSWORD_FIELD = "//input[@id='pass']";
public const string LOGIN_BUTTON = "//label[@id='loginbutton']/input";
public const string FAILED_LOGIN_TEXT = "//div/p[contains(text(),'The password
you entered is incorrect')]";
[FindsBy(How = How.XPath,Using = USER_NAME_FIELD)]
public IWebElement userNameField;
[FindsBy(How = How.XPath, Using = PASSWORD_FIELD)]
public IWebElement passwordField;
[FindsBy(How = How.XPath, Using = LOGIN_BUTTON)]
public IWebElement loginButton;
14. Події на Login-сторінці
public static LoginPage GetLoginPage() {
LoginPage loginPage = new LoginPage();
InitPage(loginPage);
return loginPage; }
public LoginPage EnterUserName(string userName){
userNameField.SendKeys(userName);
return GetLoginPage(); }
public LoginPage EnterPassword(string password){
passwordField.SendKeys(password);
return GetLoginPage(); }
public UserHomePage ClickLoginButton() {
loginButton.Click();
return UserHomePage.GetUserHomePage(); }
public LoginPage IsLoginFailed(){
TestTools.WaitingForElement(FAILED_LOGIN_TEXT);
return GetLoginPage();}
15. Тестові методи для Login-сторінки
namespace FaceBookTest
{ class LoginPageTools
{ private LoginPage loginPage = new LoginPage();
private UserHomePage userHomePage = new UserHomePage();
public LoginPageTools AssertUserName(string userName){
UserHomePage.AssertUserName(userName);
return this; } }
public LoginPageTools AssertLoginFailed(){
loginPage.IsLoginFailed();
return this;}
public LoginPageTools PleaseLogin(string userName, string password){
BaseObject.InitPage(loginPage);
loginPage.
EnterUserName(userName).
EnterPassword(password).
ClickLoginButton();
return this;
} } }
16. Елементи та події на HomePage
public const string DISPLAYED_USER_NAME =
"//img[contains(@id,'profile_pic_header')]/../span[contains(text(),'#')]";
public const string USER_NAVIGATION_MENU = "//*[@id='userNavigationLabel']";
public const string LOGOUT_BUTTON = "//input[@value='Log Out']";
[FindsBy(How = How.XPath, Using = USER_NAVIGATION_MENU)]
public IWebElement userNavigationMenu;
[FindsBy(How = How.XPath, Using = LOGOUT_BUTTON)]
public IWebElement logoutButton;
public static UserHomePage GetUserHomePage(){
UserHomePage userHomePage = new UserHomePage();
InitPage(userHomePage);
return userHomePage;
}
public UserHomePage AssertUserName(string testUserName){
TestTools.WaitingForElement(DISPLAYED_USER_NAME.Replace("#",
testUserName));
return GetUserHomePage();
}
17. Тестові методи для HomePage
namespace FaceBookTest
{
class UserHomePageTools
{
private UserHomePage userHomePage = new UserHomePage();
public UserHomePageTools PleaseLogOut()
{
BaseObject.InitPage(userHomePage);
userHomePage.userNavigationMenu.Click();
userHomePage.logoutButton.Click();
return this;
}
}
}
18. Тест
namespace FaceBookTest
{ public class LoginPageTest : BaseTest
{
private static LoginPageTools loginPageTools = new LoginPageTools();
private static UserHomePageTools userHomePageTools = new
UserHomePageTools();
[Test]
public static void UserIsAbbleToLogin(){
loginPageTools.
PleaseLogin(“fbuser@mail.com”, “fb!password13”).
AssertUserName(“FBtest User”);
UserHomePageTools.PleaseLogOut();
}
[Test]
public static void UserIsNotAbbleToLogin(){
PleaseLogin(“fbuser@mail.com”, “incorrectPassword”).
AssertLoginFailed();
}
}
}
21. Код тесту
namespace FaceBookTest
{ [Binding]
public class LoginFeatureSteps : BaseTest
{ private static LoginPageTools loginPageTools = new LoginPageTools();
private static UserHomePageTools userHomePageTools = new
UserHomePageTools();
[AfterScenario()]
public void TearDown()
{ afterClass(); }
[Given(@"FaceBook Login Page is opened")]
public void GivenFaceBookLoginPageIsOpened()
{ specFlowInit();}
[When(@"Enter credentials (.*)/(.*) and press Login button")]
public void WhenEnterCredentialsAndPressLogin(string p0, string p1)
{ loginPageTools.PleaseLogin(p0, p1); }
[Then(@"User Name (.*) is displayed on the Home Page")]
public void ThenUserNameIsDisplayedOnTheHomePage(string p0)
{ loginPageTools.AssertUserName(p0);
userHomePageTools.PleaseLogOut(); }
} }
Додати в BaseTest.сs
public void specFlowInit()
{beforeClass();
beforeTest();}