Проблема
VS2010 и поддержка TFS2010, создающая так называемые Кодированные Тесты UI. Все демонстрации, которые я нашел, запускаются с приложения WPF, уже работающего в фоновом режиме, когда Кодированный Тест UI начинается, или EXE запускается с помощью полного пути для него.
Я, однако, хотел бы запустить свое приложение WPF под тестом от кода модульного теста. Тем путем это будет также работать над сервером сборки и над рабочими копиями моей коллеги.
Как я выполняю это?
Мои открытия до сих пор
a) Это сообщение показывает, как запустить окно XAML. Но это не то, что я хочу. Я хочу запустить App.xaml, потому что он содержит ресурсы XAML и существует прикладная логика в коде позади файла.
b) Второй снимок экрана на этом сообщении показывает строку, запускающуюся с
ApplicationUnterTest calculatorWindow = ApplicationUnderTest.Launch(...);
который является концептуально в значительной степени, что я ищу, за исключением того, что снова этот пример использует полный путь исполняемый файл.
c) Поиск Google "Программно запускается, WPF" не помог также.
MyProject.App myApp = new MyProject.App();
myApp.InitializeComponent();
myApp.Run();
В итоге я использовал ApplicationUnderTest.Launch (...) ( MSDN ), который автоматически создается при записи автоматического теста с помощью Microsoft Test Manager.
Я делаю нечто подобное в VS2008 и вручную создаю тесты с помощью UI Spy, чтобы помочь мне идентифицировать элементы управления и некоторые вспомогательные методы, а не показано, чтобы запускать щелчки кнопок и проверять значения на экране. Я использую объект Process для запуска тестируемого приложения в методе TestInitialize, а в методе TestCleanup я закрываю процесс. У меня есть несколько способов полностью закрыть процесс в CleanUp. Что касается проблемы с абсолютным путем, я просто программно ищу текущий путь и добавляю исполняемый файл своего приложения. Поскольку я не знаю, сколько времени требуется для запуска приложения, я помещаю AutomationId в свое главное окно и устанавливаю его на «UserApplicationWindow» и жду, пока это станет видимым, конечно, у вас может быть что-то еще, чего вы могли бы подождать . Наконец, я использую MyTestClass в качестве базового класса и расширяю его для различных тестов.
[TestClass]
public class MyTestClass
{
private Process _userAppProcess;
private AutomationElement _userApplicationElement ;
/// <summary>
/// Gets the current directory where the executables are located.
/// </summary>
/// <returns>The current directory of the executables.</returns>
private static String GetCurrentDirectory()
{
return Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase).AbsolutePath).Replace("%20", " ");
}
[TestInitialize]
public void SetUp()
{
Thread appThread = new Thread(delegate()
{
_userAppProcess = new Process();
_userAppProcess.StartInfo.FileName =GetCurrentDirectory() + "\\UserApplication.exe";
_userAppProcess.StartInfo.WorkingDirectory = DirectoryUtils.GetCurrentDirectory();
_userAppProcess.StartInfo.UseShellExecute = false;
_userAppProcess.Start();
});
appThread.SetApartmentState(ApartmentState.STA);
appThread.Start();
WaitForApplication();
}
private void WaitForApplication()
{
AutomationElement aeDesktop = AutomationElement.RootElement;
if (aeDesktop == null)
{
throw new Exception("Unable to get Desktop");
}
_userApplicationElement = null;
do
{
_userApplicationElement = aeDesktop.FindFirst(TreeScope.Children,
new PropertyCondition(AutomationElement.AutomationIdProperty, "UserApplicationWindow"));
Thread.Sleep(200);
} while ( (_userApplicationElement == null || _userApplicationElement.Current.IsOffscreen) );
}
[TestCleanup]
public void CleanUp()
{
try
{
// Tell the application's main window to close.
WindowPattern window = _userApplicationElement.GetCurrentPattern(WindowPattern.Pattern) as WindowPattern ;
window.Close();
if (!_userAppProcess.WaitForExit(3000))
{
// We waited 3 seconds for the User Application to close on its own.
// Send a close request again through the process class.
_userAppProcess.CloseMainWindow();
}
// All done trying to close the window, terminate the process
_userAppProcess.Close();
_userAppProcess = null;
}
catch (Exception ex)
{
// I know this is bad, but catching the world is better than letting it fail.
}
}
}