This is the Software Test Automation Revealed aka S.T.A.R.
automation testing solution. It demonstrates a number of best practices in test automation with heavy emphasis on UI and Selenium based web tests. I use it in my weekly demonstrations posted on my YouTube channel called S.T.A.R.
Version 6.0 adds storing test results to a database. Repo tags v6.0
and Episode-6a
go with episode 6 part 1 of my YouTube channel.
In this project it uses MongoDB as the database of choice. There are 3 main items that get stored in MongoDB:
- A test results document which contains a number of fields.
- If the test fails it will capture the browsers page source.
- If the test fails it will capture a screenshot of the browser.
The fields stored in the test results document include:
- The fully qualified name of the test e.g. Star.Tests.DinnerPageTests.CreateDinner.
- The tests description.
- The list of test case id's.
- The list of test categories.
- The target test environment.
- The target country.
- The target language.
- The name of the web browser used to run the test.
- The version of the web browser used to run the test.
- The name of the machine that ran the test.
- The OS of the machine that ran the test.
- A flag indicating whether or not the test was executed on a CICD system.
- The test input data used to drive the test.
- The date and time the test was executed at.
- How long the test took to execute.
- The outcome of the test as reported by the NUnit test runner.
- The tests log output.
- The CICD build id or job id.
- The CICD pipeline id - which is unique to Gitlab.
- The id of the source code repository.
- The name of the branch used to run the test.
To set the tests description, test case id's and/or test categories, add attributes to the test like this:
[Test]
[Description("Verifies that a new dinner can be correctly created.")]
[Property("TestCaseIds", 1)]
[Property("TestCaseIds", 2)]
[Property("TestCaseIds", 3)]
[Category("Create")]
public void CreateDinner()
You may add as many test case id's and as many test categories as you like. But there can be only one description.
Version 5.0 adds fetching test input data from a database. In this project it uses MongoDB as the database of choice. You could use any database if you change how the database connection is made and reading the data from the database. The MongoDB NuGet's have already been added to the solution. Repo tags v5.0
and Episode-5
go with episode 5 of my YouTube channel.
Here is an example test reading and consuming data from the database:
public class DinnerPageTests : BaseStarTests
{
[Test]
public void CreateDinner()
{
var data = TestDataProvider.GetAll<DinnerModel>("STAR", "ProDinner", "Dinner");
ProDinner
.NavigateToDinners()
.CreateDinner(data)
.VerifyDinnerAdded(data);
}
}
The URL to MongoDB Community edition can be found here:
The URL to MongoDB Atlas can be found here:
Version 4.0 adds logging via Apache log4net and PostSharp. To take advantage of this you MUST download and install PostSharp. During the install you will be asked which license option you wish to use. Please select the "Use PostSharp Community" option. This option is free to use and meets our logging needs perfectly. The log4net and PostSharp NuGet's have already been added to the solution. Repo tags v4.0
and Episode-4
go with episode 4 of my YouTube channel. It demonstrates how to add automatic detailed logging by combining and taking advantage of Apache log4net and PostSharp community edition. Here's an example log of a successful test:
2021-02-14 06:55:35,342 [INFO] - Log file stored at: D:\S.T.A.R\StarTestSolution\Star.Tests\bin\Debug\netcoreapp3.1\TestResults\2021-02-14 06-55-35\Star.Tests.ProDinnerTests.Test1('One It's home time','One It's meal time','One It's chef time','One It's country time','One It's dinner time','One It's feedback time').log
2021-02-14 06:55:50,862 [INFO] - Running tests on Chrome version 88.0
2021-02-14 06:55:50,866 [INFO] - Completed Selenium WebDriver initialization. URL at start of test: https://prodinner.aspnetawesome.com/.
2021-02-14 06:55:54,003 [INFO] - >>> NavigateToHome ( [<no args>] )
2021-02-14 06:55:55,342 [INFO] - <<< NavigateToHome returned [Star.Pages.HomePage]
2021-02-14 06:55:55,342 [INFO] - >>> HomeActionOne ( [One It's home time] )
2021-02-14 06:55:55,342 [INFO] - Doing home action one
2021-02-14 06:55:55,342 [INFO] - >>> InternalMethodOne ( [<no args>] )
2021-02-14 06:55:55,342 [INFO] - >>> InternalMethodTwo ( [<no args>] )
2021-02-14 06:55:55,342 [INFO] - <<< InternalMethodTwo returned [<null>]
2021-02-14 06:55:55,342 [INFO] - <<< InternalMethodOne returned [<null>]
2021-02-14 06:55:55,342 [INFO] - <<< HomeActionOne returned [Star.Pages.HomePage]
2021-02-14 06:55:55,342 [INFO] - >>> HomeActionTwo ( [One It's home time] )
2021-02-14 06:55:55,342 [INFO] - Doing home action two
.
.
.
2021-02-14 06:56:00,337 [INFO] - >>> NavigateToFeedback ( [<no args>] )
2021-02-14 06:56:01,708 [INFO] - <<< NavigateToFeedback returned [Star.Pages.FeedbackPage]
2021-02-14 06:56:01,708 [INFO] - >>> FeedbackActionOne ( [One It's feedback time] )
2021-02-14 06:56:01,708 [INFO] - Doing feedback action one
2021-02-14 06:56:01,708 [INFO] - <<< FeedbackActionOne returned [Star.Pages.FeedbackPage]
2021-02-14 06:56:01,708 [INFO] - >>> FeedbackActionTwo ( [One It's feedback time] )
2021-02-14 06:56:01,708 [INFO] - Doing feedback action two
2021-02-14 06:56:01,708 [INFO] - <<< FeedbackActionTwo returned [Star.Pages.FeedbackPage]
2021-02-14 06:56:01,708 [INFO] - Test result: Passed
2021-02-14 06:56:01,708 [INFO] - Test duration: 00:00:23.2
Here's an example log of a failed test. Note the complete stack track and the exact line of our test code that threw the error D:\S.T.A.R\StarTestSolution\Star.Pages\HomePage.cs:line 64
:
2021-02-14 06:42:15,076 [INFO] - Log file stored at: D:\S.T.A.R\StarTestSolution\Star.Tests\bin\Debug\netcoreapp3.1\Star.Tests.ProDinnerTests.ExceptionDemonstrationTest.log
2021-02-14 06:42:20,632 [INFO] - URL at start of test: https://prodinner.aspnetawesome.com/
2021-02-14 06:42:20,632 [INFO] - Running tests on Chrome version 88.0
2021-02-14 06:42:20,635 [INFO] - Completed Selenium WebDriver initialization. URL at start of test: https://prodinner.aspnetawesome.com/.
2021-02-14 06:42:23,737 [INFO] - >>> NavigateToHome ( [<no args>] )
2021-02-14 06:42:24,514 [INFO] - <<< NavigateToHome returned [Star.Pages.HomePage]
2021-02-14 06:42:24,515 [INFO] - >>> ThrowArtificialExceptionForDemo ( [<no args>] )
2021-02-14 06:42:25,686 [ERROR] - [Star.Pages.HomePage] !! NoSuchElementException in [ThrowArtificialExceptionForDemo]:OpenQA.Selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"#InvalidId"} (Session info: chrome=88.0.4324.150)
at OpenQA.Selenium.Remote.RemoteWebDriver.UnpackAndThrowOnError(Response errorResponse)
at OpenQA.Selenium.Remote.RemoteWebDriver.Execute(String driverCommandToExecute, Dictionary`2 parameters)
at OpenQA.Selenium.Remote.RemoteWebDriver.FindElement(String mechanism, String value)
at OpenQA.Selenium.Remote.RemoteWebDriver.FindElementByCssSelector(String cssSelector)
at OpenQA.Selenium.By.<>c__DisplayClass23_0.<CssSelector>b__0(ISearchContext context)
at OpenQA.Selenium.By.FindElement(ISearchContext context)
at OpenQA.Selenium.Remote.RemoteWebDriver.FindElement(By by)
at Star.Pages.HomePage.ThrowArtificialExceptionForDemo() in D:\S.T.A.R\StarTestSolution\Star.Pages\HomePage.cs:line 64
2021-02-14 06:42:25,728 [INFO] - Test result: Failed:Error
2021-02-14 06:42:25,728 [INFO] - Test duration: 00:00:07.2
Optionally you can add explicit logging statements such as the Test.Logger.Info
call demonstrated here:
public HomePage HomeActionTwo(string homeMsg)
{
Assert.AreEqual(homeMsg, Test.DataCache<SimplePOCO>().Announcement);
Test.Logger.Info("Doing home action two");
return this;
}
Repo tags v3.0
and Episode-3
go with episode 3 of my YouTube channel. It demonstrates how to take advantage of Fluent Assertions
. Here is an example of a fluent assertion:
public HomePage VerifyCurrentPageSize()
{
DinnersGridRows.Count.Should().Be(Test.DataCache<HomePageModel>().ExpectedPageSize);
return this;
}
Repo tags v2.0
and Episode-2
go with episode 2 of my YouTube channel. It demonstrates the concept of a Global Data Cache
and how this is advantageous in web tests. Here is an example of how to use the global data cache. Note the Test.DataCache<>
lines of code:
namespace Star.Models
{
public class SimplePOCO
{
public string Announcement { get; set; }
}
}
public HomePage HomeActionOne(string homeMsg)
{
// Store homeMsg in the global data cache for this test
Test.DataCache<SimplePOCO>().Announcement = homeMsg;
TestContext.WriteLine("Doing home action one");
return this;
}
public HomePage HomeActionTwo(string homeMsg)
{
// Verify that the value of the Announcement field stored in the Global Data Cache equals homeMsg
Assert.AreEqual(homeMsg, Test.DataCache<SimplePOCO>().Announcement);
TestContext.WriteLine("Doing home action two");
return this;
}
Repo tags v1.0
and Episode-1
go with episode 1 of my YouTube channel. It demonstrates the advantages of fluent style test coding. Here is an example of a fluent style test:
[Test]
public void Test()
{
ProDinner
.NavigateToHome()
.HomeActionOne()
.HomeActionTwo()
.NavigateToMeals()
.MealsActionOne()
.MealsActionTwo()
.NavigateToChefs()
.ChefActionOne()
.ChefActionTwo()
.NavigateToCountries()
.CountryActionOne()
.CountryActionTwo()
.NavigateToDinners()
.DinnerActionOne()
.DinnerActionTwo()
.NavigateToFeedback()
.FeedbackActionOne()
.FeedbackActionTwo();
}