Sunday, September 20, 2015

Defect Statuses | Best Practices

The “Defect Life cycle” contain multiple stages that involve in the process, during this time the bug status can change multiple times depends on the investigation/decision that’s made by the owner of each phase.


Understanding the importance of each status and how it’s affecting the decision makers, is critical when you want to implement an effective DLC process, the next table will review the available statuses that mandatory for every DLC process no matter what is the tested software.

Status 
Description
New
A New bug is identified and reported in the bug tracking system,
The bug will automatically receive the status “New”, this status will remain until the owner (Manager, Tech lead, Testing manager Etc.) will review and approve/decline this bug.
Assigned
The bug owner review the bug (Current state is “New”), depends on the quality of the bug the owner will decide “What is the next step?”
In case that the bug is detailed and approved, the owner will assignee this bug to the relevant developer (that need to fix this bug). 
Open
This status become relevant in case that a bug with status “New” is approved by the owner and assigned to the relevant developer.
Fixed
This status is set by the developer that makes the code modifications, the basic procedure that involve before a developer can put this status:
1.       Developer receive the bug that assigned to him.
2.       Developer reviews the bug and ask the relevant questions.
3.       The Developer makes the necessary code modification.
4.       Developer verifies his changes.
5.       The Developer changed the bug status to “Fixed”.
6.       A Developer can add additional testing scenarios for verification (in addition to the original bug scenario).
7.       The bug is moved to QA for verifications.
Duplicate
This status is set in any case that the new opened bug is already opened in the bug tracking system.
Invalid
This status is given to a bug in different cases that the developer can prove that the bug is not valid, there are many cases that can support this status, examples:
-          Bug that opened against the software requirements and specifications.
-          Bug that opened on unsupported architectures.
-          Bug that opened based on invalid scenario.
Reopened
When a developer mark bug as “Fixed”, the bug moved to QA verification, a “Reopen” status is set in any case that the bug is reproduced with the original test scenario.
When a tester change the bug to this status, the bug returns to the Dev team for further investigation and code modifications.
Note!
If the bug is reproduced with Different scenario we sometimes prefer to open a new bug and not “Reopen” the current one.
Wontfix
This status is set on any bug that the dev. team cannot fix, there are a few basic reasons that may lead to this status:
-          Technical limitations.
-          There is no economic justification to fix this bug.
Later Version
This status is set in any case that the bug is moved to a future version and not fixed on the current one.
The main reasons that may lead to such decision:
-          A Bug that has low priority.
-          There is not time to fix.
-          The fix can trigger new risks that the QA cannot re test among the current timelines.
-          Bugs with minor severity.
By Spec/design
This status is usually set on bugs that opened by a tester that unfamiliar with the software design/spec, in such case the tester reports a valid behavior of the application as “Bug” although the behavior is valid and expectable.
My Personal opinion:
Every bug that closed with this status is a shame for the QA person that opened it, the basic thing for every tester is to be familiar with the project requirements and design.
Cant reproduced /Worksforme
This status is set by a developer that execute the scenarios that described in the bug, but the outcome is the one that expected based on the requirements.
The basic scenario:
1.       Developer receive bug.
2.       Developer executes the attached scenario.
3.       Developer examine the scenario results.
4.       The results valid and based on the SRS documentation.
5.       The Developer is marked the bug as “Worksforme” or “Could not reproduce”.
6.       The developer notifies the tester that the attached scenario is working as expected,
7.       The tester can try to reproduce the bug.
Verified/ Closed
When a developer made the relevant code changes, the bug is moved to QA team for verifications, in this stage the relevant tester will verify that the code changes are working as expected and the bug is not reproduced again.
In my opinion a bug can set has “Verified””, only after that few basic criteria are answered:
1.       The original bug is removed.
2.       The tester understands d the code changes and must think about the consequences.
3.       The tester is making sure that the code changes are not affect other components.

Saturday, September 12, 2015

Lesson #19 -Selenium WebDriver – Testing in the real world


Overview


In the last two months, I published more than twenty articles that examine the selenium framework, during this time period I received hundreds of requests to add practical examples that people can use during the actual development cycles.


Well, you asked so I replied with this article that will examine a real use case scenario of validating a WebPage user authentication window, please read and copy the code that you need, enjoy.

The webpage specification
  • The login window contain two fields (Username/Password).
  • The login window contain two buttons (login/Cancel).
  • In case of valid login the user is directed to my blog address (http://www.dtvisiontech.com).
  • In case of Invalid login the user will receice a notification("Error Password or Username").
  • Valid credentials (User: David , Pass: Tzemach).
The WebBrowser code
I added the HTML code that I used in this example (just copy to notepad and save as HTML)
<html><head>  <title>Authentication Tests</title></head><body><h1>Login page</h1><form name="login">Username<input type="text" name="userid"/>Password<input type="password" name="pswrd"/><input type="button" onclick="check(this.form)" value="Login"/><input type="reset" value="Cancel"/></form><script language="javascript">function check(form) { /*function to check userid & password*//*the following code checkes whether the entered userid and password are matching*/if(form.userid.value == "David" && form.pswrd.value == "Tzemach") {window.open('http://www.dtvisiontech.com')/*opens the target page while Id & password matches*/}else {alert("Error Password or Username")/*displays error message*/}}</script></body></html>
The result:
The Code of our application
I build my code with the POM approach to demonstrate how can you build a simple and readable code in your own projects, pay attention to the importance and relevance of each class that I describe.

Class 1: Object Mapping

class ObjectMapphing
    {
        //Creating a general Element for all functions
        public static IWebElement General_Element_for_All_Functions = null;
        //Login page - Title
        public static IWebElement Login_Page_Title(IWebDriver FirefoxDriver)
        {
            General_Element_for_All_Functions = FirefoxDriver.FindElement(By.XPath("/html/body/h1"));           
            return General_Element_for_All_Functions;
        }
        //The User Name Field
        public static IWebElement UserNameField(IWebDriver FirefoxDriver)
        {
            General_Element_for_All_Functions = FirefoxDriver.FindElement(By.Name("userid"));           
            return General_Element_for_All_Functions;
        }
        //The Password field
        public static IWebElement PasswordField(IWebDriver FirefoxDriver)
        {
            General_Element_for_All_Functions = FirefoxDriver.FindElement(By.Name("pswrd"));
            return General_Element_for_All_Functions;
        }
        //The Login Button
        public static IWebElement LoginButton(IWebDriver FirefoxDriver)
        {
            General_Element_for_All_Functions = FirefoxDriver.FindElement(By.XPath("/html/body/form/input[3]"));
            return General_Element_for_All_Functions;
        }
        //The Cancel Button
        public static IWebElement CancelButton(IWebDriver FirefoxDriver)
        {
            General_Element_for_All_Functions = FirefoxDriver.FindElement(By.Name("pswrd"));
            return General_Element_for_All_Functions;
        }
        //Blog Main Title(Used in the verification scenario)
        public static IWebElement Main_Title_Verification(IWebDriver FirefoxDriver)
        {
            General_Element_for_All_Functions = FirefoxDriver.FindElement(By.XPath("//h1[@class='title']"));
            return General_Element_for_All_Functions;
        }
        //Will be used to handle the failed login attempt
        public static string JavaScriptValidation(IWebDriver FirefoxDriver , String ValidationString)
        {
        IAlert alert = FirefoxDriver.SwitchTo().Alert();
        string PopUpText = alert.Text;       
        return PopUpText;               
        }       
    }

Class 2: Debugg Class

class DebuggClass
    {               
       //Print the test results into a .TXT file(V.1)
        public static void PrintToFile(String FileInput , String Expected)
        {
            using (FileStream fs = new FileStream(@"d:\Debugg.txt", FileMode.Append, FileAccess.Write))
            using (StreamWriter sw = new StreamWriter(fs))
            {
                sw.WriteLine("---------------------------------------------------------------------" + Environment.NewLine + FileInput + Expected + Environment.NewLine + "---------------------------------------------------------------------" + Environment.NewLine);              
            }
        }
        //Print the test results into a .TXT file(V.2)
        public static void PrintToFileV2(String FileInput)
        {
            using (FileStream fs = new FileStream(@"d:\Debugg.txt", FileMode.Append, FileAccess.Write))
            using (StreamWriter sw = new StreamWriter(fs))
            {
                sw.WriteLine( FileInput+Environment.NewLine);
            }
        }
        //Open the file when the execution ended
        public static void OpenFile()
        {
            System.Diagnostics.Process.Start(@"d:\Debugg.txt");
        }
        //Print the Execution Start/End time
        public static void Start_And_End_of_the_Execution(int StartOrEnd)
        {
            switch (StartOrEnd)
            {
                //The START time of the test execution
                case 0:
                    PrintToFileV2("---------------------------------------------------------------------");
                    PrintToFileV2("Test Execition is started |  Start Time : "+ DateTime.Now.ToString());
                    PrintToFileV2("---------------------------------------------------------------------");
                    break;
                //The END time of the test execution
                case 1:
                    PrintToFileV2("---------------------------------------------------------------------");
                    PrintToFileV2("Test Execition is Ended     |  End Time" + DateTime.Now.ToString());
                    PrintToFileV2("---------------------------------------------------------------------");
                    break;
                default:
                    break;
            }           
        }

 

Class 3: The Main class

  [TestClass]
    public class UnitTest1
    {
        IWebDriver FirefoxInstance;
        [TestInitialize]
        public void TestSetup()
        {
            FirefoxInstance = new FirefoxDriver();
            FirefoxInstance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(150));
            FirefoxInstance.Navigate().GoToUrl("file:///C:/Users/D/Desktop/d.html");           
        }
        [TestCleanup]
        public void CloseTest()
        {
            FirefoxInstance.Quit();           
        }
        [TestMethod]
        public void WebPageData()
        {
            DebuggClass.Start_And_End_of_the_Execution(0); //0 - Starting the tests , 1- Ending the test
            DebuggClass.PrintToFile("Test Name: Web Page Data" + Environment.NewLine + "Tab Name: " + FirefoxInstance.Title + Environment.NewLine, "Url Name: " + FirefoxInstance.Url);           
        }
      
        [TestMethod]
        public void TitleValidation()
        {
            if (ObjectMapphing.Login_Page_Title(FirefoxInstance).Text.Equals("Login page") == true)
            {
                DebuggClass.PrintToFile("Test Name: Title Validation" + Environment.NewLine + "Status = Pass" + Environment.NewLine +"Exp: Login page"  + Environment.NewLine +  "Actual:", ObjectMapphing.Login_Page_Title(FirefoxInstance).Text);
            }
            else
            {
                DebuggClass.PrintToFile("Test Name: Title Validation" + Environment.NewLine + "Status = Failed" + Environment.NewLine + "Exp: Login page" + Environment.NewLine + "Actual:", ObjectMapphing.Login_Page_Title(FirefoxInstance).Text);               
            }
        }
        [TestMethod]
        public void Validate_Objects_In_Page()
        {
            if (ObjectMapphing.UserNameField(FirefoxInstance).Displayed == true && ObjectMapphing.UserNameField(FirefoxInstance).Enabled == true)
            {
                DebuggClass.PrintToFile("Test Name: Validate Page Objects (User Name Field)" + Environment.NewLine + "Status = Pass" + Environment.NewLine + "Exp: Object is Available" + Environment.NewLine,"");
            }
            else
            {
                DebuggClass.PrintToFile("Test Name: Validate Page Objects (User Name Field)" + Environment.NewLine + "Status = Failed" + Environment.NewLine + "Exp: Object is Available" + Environment.NewLine, "Actual:The Object Is Not Available");
            }
            if (ObjectMapphing.PasswordField(FirefoxInstance).Displayed == true && ObjectMapphing.PasswordField(FirefoxInstance).Enabled == true)
            {
                DebuggClass.PrintToFile("Test Name: Validate Page Objects (Password Field)" + Environment.NewLine + "Status = Pass" + Environment.NewLine + "Exp: Object is Available" + Environment.NewLine, "");
            }
            else
            {
                DebuggClass.PrintToFile("Test Name: Validate Page Objects (Password Field)" + Environment.NewLine + "Status = Failed" + Environment.NewLine + "Exp: Object is Available" + Environment.NewLine, "Actual:The Object Is Not Available");
            }
            if (ObjectMapphing.LoginButton(FirefoxInstance).Displayed == true && ObjectMapphing.LoginButton(FirefoxInstance).Enabled)
            {
                DebuggClass.PrintToFile("Test Name: Validate Page Objects (Log in Button)" + Environment.NewLine + "Status = Pass" + Environment.NewLine + "Exp: Object is Available" + Environment.NewLine, "");
            }
            else
            {
                DebuggClass.PrintToFile("Test Name: Validate Page Objects (Log in Button)" + Environment.NewLine + "Status = Failed" + Environment.NewLine + "Exp: Object is Available" + Environment.NewLine, "Actual:The Object Is Not Available");
            }
            if (ObjectMapphing.CancelButton(FirefoxInstance).Displayed == true && ObjectMapphing.CancelButton(FirefoxInstance).Enabled)
            {
                DebuggClass.PrintToFile("Test Name: Validate Page Objects (Cancel Button)" + Environment.NewLine + "Status = Pass" + Environment.NewLine + "Exp: Object is Available" + Environment.NewLine, "");
            }
            else
            {
                DebuggClass.PrintToFile("Test Name: Validate Page Objects (Cancel Button)" + Environment.NewLine + "Status = Failed" + Environment.NewLine + "Exp: Object is Available" + Environment.NewLine, "Actual:The Object Is Not Available");
               
            }                   
        }
        [TestMethod]
        public void Validate_Log_In_Failed_attempt()
        {
            ObjectMapphing.UserNameField(FirefoxInstance).SendKeys("Invalid User Name");
            ObjectMapphing.PasswordField(FirefoxInstance).SendKeys("Invalid User Password");
            ObjectMapphing.LoginButton(FirefoxInstance).Click();
            ObjectMapphing.JavaScriptValidation(FirefoxInstance,"");
            if (ObjectMapphing.JavaScriptValidation(FirefoxInstance, "") == "Error Password or Username")
            {
                DebuggClass.PrintToFile("Test Name: Validate Log In Failed attempt" + Environment.NewLine + "Status = Pass" + Environment.NewLine + "Exp: Error Password or Username" + Environment.NewLine + "Actual:", ObjectMapphing.JavaScriptValidation(FirefoxInstance, ""));
            }
            else
            {
                DebuggClass.PrintToFile("Test Name: Validate Log In Failed attempt" + Environment.NewLine + "Status = Failed" + Environment.NewLine + "Exp: Error Password or Username" + Environment.NewLine + "Actual:", ObjectMapphing.JavaScriptValidation(FirefoxInstance, ""));
            }
                       
            //Option 2 :
            //Assert.AreEqual(ObjectMapphing.JavaScriptValidation(FirefoxInstance, ""), "Error Password or Username");
        }
        [TestMethod]
        public void Validate_Log_In_Success_attempt()
        {
            // Store the current window handle
            string primaryWindowHandle = FirefoxInstance.CurrentWindowHandle;
            //Perform the click operation that opens new window
            ObjectMapphing.UserNameField(FirefoxInstance).SendKeys("David");
            ObjectMapphing.PasswordField(FirefoxInstance).SendKeys("Tzemach");                       
            ObjectMapphing.LoginButton(FirefoxInstance).Click();
           
           //New Array that host the new handle ID
           IList<string> OpenWindows = FirefoxInstance.WindowHandles;
           //Switch to the new opned window
           FirefoxInstance.SwitchTo().Window(OpenWindows[1].ToString());
           //Validate the Log-in attempt
           if ((ObjectMapphing.Main_Title_Verification(FirefoxInstance).Text) == "David Tzemach - Technical Vision")
           {
               DebuggClass.PrintToFile("Test Name: Validate Log In Success attempt" + Environment.NewLine + "Status = Pass" + Environment.NewLine + "Exp: David Tzemach - Technical Vision" + Environment.NewLine + "Actual:", ObjectMapphing.Main_Title_Verification(FirefoxInstance).Text);
              
//Close the current window
               FirefoxInstance.Close();
               //Return to main Window
               FirefoxInstance.SwitchTo().Window(primaryWindowHandle);
           }
           else
           {
               DebuggClass.PrintToFile("Test Name: Validate Log In Success attempt" + Environment.NewLine + "Status = Failed" + Environment.NewLine + "Exp: Login page" + Environment.NewLine + "Actual:", "Failure in validation");               
           }
          
            //
           DebuggClass.Start_And_End_of_the_Execution(1);
           DebuggClass.OpenFile();
        }
        private void LoadPage(int NumberOfSeconds , string Url)
        {
           FirefoxInstance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(NumberOfSeconds));
           FirefoxInstance.Navigate().GoToUrl(Url);
        }
        }                 
    }

Test Results:

 

 

 

 

 


---------------------------------------------------------------------
--------------------------------------------------------------------
Test Execition is started |  Start Time : 07/08/2015 10:59:49
---------------------------------------------------------------------
---------------------------------------------------------------------
Test Name: Web Page Data
Tab Name: Authentication Tests
Url Name: file:///C:/Users/D/Desktop/d.html
---------------------------------------------------------------------
---------------------------------------------------------------------
Test Name: Title Validation
Status = Pass
Exp: Login page
Actual:Login page
---------------------------------------------------------------------
---------------------------------------------------------------------
Test Name: Validate Page Objects (User Name Field)
Status = Pass
Exp: Object is Available
---------------------------------------------------------------------
--------------------------------------------------------------------
Test Name: Validate Page Objects (Password Field)
Status = Pass
Exp: Object is Available
---------------------------------------------------------------------
---------------------------------------------------------------------
Test Name: Validate Page Objects (Log in Button)
Status = Pass
Exp: Object is Available
---------------------------------------------------------------------
---------------------------------------------------------------------
Test Name: Validate Page Objects (Cancel Button)
Status = Pass 
Exp: Object is Available
---------------------------------------------------------------------
---------------------------------------------------------------------
Test Name: Validate Log In Failed attempt
Status = Pass
Exp: Error Password or Username
Actual:Error Password or Username
---------------------------------------------------------------------
---------------------------------------------------------------------
est Name: Validate Log In Success attempt
Status = Pass
Exp: David Tzemach - Technical Vision
Actual:David Tzemach - Technical Vision
---------------------------------------------------------------------
---------------------------------------------------------------------
Test Execition is Ended     |  End Time07/08/2015 11:00:19
---------------------------------------------------------------------
---------------------------------------------------------------------

     

My Presentations