Skip to content

Instantly share code, notes, and snippets.

@pvandervelde
Last active August 29, 2015 13:56
Show Gist options
  • Save pvandervelde/9202656 to your computer and use it in GitHub Desktop.
Save pvandervelde/9202656 to your computer and use it in GitHub Desktop.
<Menu AutomationProperties.AutomationId="{x:Static infrastructure:MainMenuAutomationIds.Menu}"
DockPanel.Dock="Top"
IsMainMenu="True">
/// <summary>
/// Defines the automation IDs for the main menu.
/// </summary>
internal static class MainMenuAutomationIds
{
/// <summary>
/// The automation ID for the File menu.
/// </summary>
public const string File = "Explorer.MainMenu.File";
/// <summary>
/// The automation ID for the File - Close menu.
/// </summary>
public const string FileClose = "Explorer.MainMenu.File.Close";
}
/// <summary>
/// Stores marketing information about the company.
/// </summary>
internal static class CompanyInformation
{
/// <summary>
/// The name of the company.
/// </summary>
public const string CompanyName = "My Company Ltd.";
/// <summary>
/// The name of the path in the file system related to the company name.
/// </summary>
public const string CompanyPathName = "MyCompany";
/// <summary>
/// The URL of the main website of the company.
/// </summary>
public const string CompanyUrl = @"http://www.mycompany.com";
}
// Minimize directly on start-up so that we can't take focus on our own window
MinimizeConsoleWindow();
var globalResult = new TestResult();
try
{
// Initialize the container
var container = DependencyInjection.Load();
InitializeWhite(container);
var reporters = container.Resolve<IEnumerable<IReporter>>();
var log = container.Resolve<Log>();
var applicationPath = ApplicationProxies.GetApolloExplorerPath(log);
if (string.IsNullOrEmpty(applicationPath))
{
var message = "Could not find application path.";
reporters.ForEach(r => r.AddErrorMessage(message));
globalResult.AddError(message);
}
// Select the type of test to execute
var views = container.ResolveKeyed<IUserInterfaceVerifier>(typeof(VerifyViews));
var projects = container.ResolveKeyed<IUserInterfaceVerifier>(typeof(VerifyProject));
foreach (var testCase in views.TestsToExecute().Append(projects.TestsToExecute()))
{
var message = string.Format(
CultureInfo.InvariantCulture,
"Starting: {0}",
testCase.Name);
reporters.ForEach(r => r.AddInformationalMessage(message));
var localResult = ExecuteTestCase(testCase, log, applicationPath);
if (localResult.Status == TestStatus.Passed)
{
var succesMessage = string.Format(
CultureInfo.InvariantCulture,
"Successfully completed test: {0}",
testCase.Name);
reporters.ForEach(r => r.AddInformationalMessage(succesMessage));
}
else
{
foreach (var error in localResult.Errors)
{
var failMessage = error;
globalResult.AddError(error);
reporters.ForEach(r => r.AddErrorMessage(failMessage));
}
}
}
}
catch (Exception e)
{
var message = string.Format(
CultureInfo.InvariantCulture,
"Unhandled exception occurred during the execution of the regression tests. Error was: {0}",
e);
globalResult.AddError(message);
}
return globalResult.Status == TestStatus.Passed ? NormalApplicationExitCode : UnhandledExceptionApplicationExitCode;
private static TestResult ExecuteTestCase(TestStep testCase, Log testLog, string applicationPath)
{
const string prefix = "Execute test case";
var count = 0;
var hasPassed = false;
var results = Enumerable.Range(0, TestConstants.MaximumRetryCount)
.Select(i => new TestResult())
.ToArray();
while ((count < TestConstants.MaximumRetryCount) && (!hasPassed))
{
testLog.Info(
prefix,
string.Format(
CultureInfo.InvariantCulture,
"Executing test case: {0}. Iteration: {1}",
testCase.Name,
count + 1));
try
{
using (var context = new TestContext(applicationPath, testLog))
{
TestResult local;
try
{
local = testCase.Test(context.Application, testLog);
foreach (var error in local.Errors)
{
results[count].AddError(error);
}
}
catch (Exception e)
{
testLog.Error(prefix, e.ToString());
results[count].AddError(
string.Format(
CultureInfo.InvariantCulture,
"Error in test case: {0}. Error was: {1}",
testCase.Name,
e));
}
finally
{
testLog.Info(
prefix,
string.Format(
CultureInfo.InvariantCulture,
"Completed test case: {0}. Result: {1}",
testCase.Name,
results[count].Status));
}
}
}
catch (Exception e)
{
results[count].AddError(
string.Format(
CultureInfo.InvariantCulture,
"Test case failed for: {0}. Iteration: {1}. Error: {2}",
testCase.Name,
count + 1,
e));
}
hasPassed = results[count].Status == TestStatus.Passed;
count++;
}
return results[count - 1];
}
/// <summary>
/// Returns the 'File - Close' menu item.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="log">The log object.</param>
/// <returns>The 'File - Close' menu item.</returns>
public static Menu GetFileCloseMenuItem(Application application, Log log)
{
const string prefix = "Menus - Get 'File - Close' menu";
var menu = GetMainMenu(application, log);
if (menu == null)
{
return null;
}
var fileMenuSearchCriteria = SearchCriteria.ByAutomationId(MainMenuAutomationIds.File);
var closeSearchCriteria = SearchCriteria.ByAutomationId(MainMenuAutomationIds.FileClose);
return Retry.Times(
() =>
{
log.Debug(prefix, "Trying to get the 'File - Close' menu item.");
var menuItem = menu.MenuItemBy(fileMenuSearchCriteria, closeSearchCriteria);
if (menuItem == null)
{
log.Error(prefix, "Failed to find the 'File - Close' menu item.");
}
return menuItem;
});
}
/// <summary>
/// Closes a project via the 'File - Close' menu.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="log">The log object.</param>
/// <exception cref="RegressionTestFailedException">
/// Thrown if the 'File - Close' menu could not be invoked for some reason.
/// </exception>
public static void CloseProjectViaFileCloseMenuItem(Application application, Log log)
{
const string prefix = "Menus - Close project via File menu";
var closeMenu = GetFileCloseMenuItem(application, log);
if (closeMenu == null)
{
throw new RegressionTestFailedException(prefix + ": Failed to get the 'File - Close' menu item.");
}
try
{
closeMenu.Click();
}
catch (Exception e)
{
throw new RegressionTestFailedException(prefix + ": Failed to click the 'File - Close' menu item.", e);
}
}
//-----------------------------------------------------------------------
// <copyright company="P. van der Velde">
// Copyright (c) P. van der Velde. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
using System;
using System.Threading;
namespace Test.Regression.Explorer
{
/// <summary>
/// Defines methods that retry an action several times.
/// </summary>
internal static class Retry
{
/// <summary>
/// Retries the given action a number of times before giving up.
/// </summary>
/// <typeparam name="T">The type of object that is returned.</typeparam>
/// <param name="func">The function that should return the object.</param>
/// <returns>The object or <see langword="null" /> if no value could be obtained.</returns>
public static T Times<T>(Func<T> func) where T : class
{
return Times(func, TestConstants.MaximumRetryCount);
}
/// <summary>
/// Retries the given action a number of times before giving up.
/// </summary>
/// <typeparam name="T">The type of object that is returned.</typeparam>
/// <param name="func">The function that should return the object.</param>
/// <param name="maximumNumberOfTries">The number of times the action should be attempted before giving up.</param>
/// <returns>The object or <see langword="null" /> if no value could be obtained.</returns>
public static T Times<T>(Func<T> func, int maximumNumberOfTries) where T : class
{
return Times(
func,
() => { },
maximumNumberOfTries);
}
/// <summary>
/// Retries the given action a number of times before giving up.
/// </summary>
/// <typeparam name="T">The type of object that is returned.</typeparam>
/// <param name="func">The function that should return the object.</param>
/// <param name="waitFunc">The function that is called to wait.</param>
/// <returns>The object or <see langword="null" /> if no value could be obtained.</returns>
public static T Times<T>(Func<T> func, Action waitFunc) where T : class
{
return Times(func, waitFunc, TestConstants.MaximumRetryCount);
}
/// <summary>
/// Retries the given action a number of times before giving up.
/// </summary>
/// <typeparam name="T">The type of object that is returned.</typeparam>
/// <param name="func">The function that should return the object.</param>
/// <param name="waitFunc">The function that is called to wait.</param>
/// <param name="maximumNumberOfTries">The number of times the action should be attempted before giving up.</param>
/// <returns>The object or <see langword="null" /> if no value could be obtained.</returns>
public static T Times<T>(Func<T> func, Action waitFunc, int maximumNumberOfTries) where T : class
{
int retryCount = 0;
T value = null;
while ((value == null) && (retryCount < maximumNumberOfTries))
{
try
{
value = func();
}
catch (Exception)
{
value = null;
}
try
{
waitFunc();
}
catch (Exception)
{
// Just ignore it ...
}
retryCount++;
}
return value;
}
}
}
//-----------------------------------------------------------------------
// <copyright company="P. van der Velde">
// Copyright (c) P. van der Velde. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
using System;
using TestStack.White;
namespace Test.Regression.Explorer
{
/// <summary>
/// Defines a single test case.
/// </summary>
internal sealed class TestStep
{
/// <summary>
/// The name of the test case.
/// </summary>
private readonly string m_Name;
/// <summary>
/// The action that should be executed to run the test case.
/// </summary>
private readonly Func<Application, Log, TestResult> m_TestCase;
/// <summary>
/// Initializes a new instance of the <see cref="TestStep"/> class.
/// </summary>
/// <param name="name">The name of the test case.</param>
/// <param name="testCase">The action that is executed when the test case is executed.</param>
/// <exception cref="ArgumentNullException">
/// Thrown if <paramref name="name"/> is <see langword="null" />.
/// </exception>
/// <exception cref="ArgumentException">
/// Thrown if <paramref name="name"/> is an empty string.
/// </exception>
/// <exception cref="ArgumentNullException">
/// Thrown if <paramref name="testCase"/> is <see langword="null" />.
/// </exception>
public TestStep(string name, Func<Application, Log, TestResult> testCase)
{
{
Lokad.Enforce.Argument(() => name);
Lokad.Enforce.Argument(() => name, Lokad.Rules.StringIs.NotEmpty);
Lokad.Enforce.Argument(() => testCase);
}
m_Name = name;
m_TestCase = testCase;
}
/// <summary>
/// Gets the name of the test case.
/// </summary>
public string Name
{
get
{
return m_Name;
}
}
/// <summary>
/// Gets the test action.
/// </summary>
public Func<Application, Log, TestResult> Test
{
get
{
return m_TestCase;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment