понедельник, 30 июня 2014 г.

How to provide MSAA Name for MFC edit controls

Microsoft Active Accessibility (MSAA) can be used in GUI test automation or for accessibility. For test automation purposes, IAccessible::get_accName can be used to retrieve name of an edit box. To make this to work for MFC based applications, the tab order sequence should be modified such that the static label at the left of the edit box is one number lower. For example, if the edit box's tab order number is 5, the static label on the left should have tab order of 4. For MFC based application created using VS2010, menu Format | Tab Order (Ctrl + D) should show the order sequence graphically.

Note that this is applicable to the following test automation tools/frameworks:
- Test Partner
- Rational Robot
- UI Automation

Just to stress this out again, you need to have a static label to the left of the edit box for this work.

Enjoy!

References:
http://msdn.microsoft.com/en-us/library/dd373597(v=VS.85).aspx
http://msdn.microsoft.com/en-us/library/dd318483(VS.85).aspx 

http://8thstring.blogspot.ru/2010/11/how-to-provide-msaa-name-for-mfc-edit.html

среда, 25 июня 2014 г.

PageObjects pattern

Как тестировать поиск

http://alexeybulat.blogspot.ru/2009/05/search.html

Пример 1. Поиск пользователя
Пример 2. Поиск при разных типах граничных условий
Пример 3. Использование Wildcard символов

Особенности тестирования инсталляторов

http://alexeybulat.blogspot.ru/2009/03/installation-testing.html

Распишем подробнее, "Что?" необходимо проверить, для оценки правильности работы инсталлятора:
  • Установка (Инсталляция)
    1. Корректность списка файлов в инсталляционном пакете:
      1. при выборе различных типов установки, либо установочных параметров список файлов и пути к ним также могут отличаться.
      2. отсутствие лишних файлов (проектные файлы, не включенные в инсталляционный пакет, не должны попасть на диск пользователя)
    2. Регистрация приложения в ОС
    3. Регистрация расширений для работы с файлами:
      1. для новых расширений
      2. для уже существующих расширений
    4. Права доступа пользователя, который ставит приложение:
      1. права на работу с системным реестром
      2. права на доступ к файлам и папкам, например %Windir%\system32
    5. Корректность работы мастера установки (Installation Wizard)
    6. Инсталляция нескольких приложений за одни заход
    7. Установка одного и того же приложения в разные рабочие директории одной рабочей станции
  • Обновление
    1. Правильность списка файлов, а так же отсутствие лишних файлов:
      1. проверка списка файлов при разных параметрах установки
      2. отсутствие лишних файлов
    2. Обратная совместимость создаваемых данных
      1. сохранность и корректная работа созданных до обновления данных
      2. возможность корректной работы старых версий приложения с данными, созданными в новых версиях
    3. Обновление при запущенном приложении
    4. Прерывание обновления
  • Удаление (Деинсталляция)
    1. Корректное удаление приложения:
      1. удаление из системного реестра установленных в процессе инсталляции библиотек и служебных записей
      2. удаление физических файлов приложения.
      3. удаление/восстановление предыдущих файловых ассоциаций.
      4. сохранность файлов созданных за время работы с приложением
    2. Удаление при запущенном приложении
    3. Удаление с ограниченным доступом к папке приложения
    4. Удаление пользователем без соответствующих прав

stdafx.h

http://habrahabr.ru/company/pvs-studio/blog/227521/

Можно существенно сократить объем работы, которую должен проделать препроцессор при компиляции проекта. Идея в том, чтобы заранее препроцессировать группу файлов и затем просто подставлять готовый фрагмент текста.

Поиск Memory Leaks в VisualStudio

Поиск и устранение утечек памяти в Visual Studio.
Найти утечки памяти в программе можно следующим способом:
Первое что следует сделать:
В заголовочный файл который включается всеми другими файлами(например "stdafx.h") в начало нужно поместить следующие строки:
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
Этим мы заменяем функции malloc и free другими malloc_dbg и free_dbg, которые будут выполнять проверки.
Затем в функцию, где начинается работа программы(WinMain()) в начало добавляем следующее:
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
Благодаря этой функции после возвращения вашей программой контроля системе, все утечки памяти будут напечатаны в окне Output в следующем виде:
Detected memory leaks!
Dumping objects ->
C:\PROGRAM FILES\VISUAL STUDIO\MyProjects\leaktest\leaktest.cpp(20) : {18} 
normal block at 0x00780E80, 64 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
В фигурных скобках показывается номер выделения памяти, которая не была удалена.
Можно перейти к месту в коде, где прошло выделение памяти по двойному клику на строчке
  C:\PROGRAM FILES\VISUAL STUDIO\MyProjects\leaktest\leaktest.cpp(20) : {18}
, но обычно это не сильно помогает.
Также можно изменить место, куда будет писаться информация об утечках с помощью функции _CrtSetReportMode(см. MSDN)
Теперь переходим ко второй части - избавление от утечек:
В начало функции, где начинается работа программы нужно добавить:
_CrtSetBreakAlloc(num); // где num - номер утечки
после этого запустить Debug режим.
В момент выделения вылетит окошко с ошибкой ("User breakpoint").
Нужно нажать кнопку break и перемещаться вверх в окне Call Stack до вашей функции, которая вызвала выделение неудалённой памяти.

вторник, 24 июня 2014 г.

101 LINQ Samples

http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b

Learn how to use LINQ in your applications with these code samples, covering the entire range of LINQ functionality and demonstrating LINQ with SQL, DataSets, and XML.

Query Expression Syntax for Standard Query Operators

http://msdn.microsoft.com/ru-ru/library/bb882642.aspx

            class Pet
            {
                public string Name { get; set; }
                public int Age { get; set; }
            }

            public static void AllEx()
            {
                // Create an array of Pets.
                Pet[] pets = { new Pet { Name="Barley", Age=10 },
                               new Pet { Name="Boots", Age=4 },
                               new Pet { Name="Whiskers", Age=6 } };

                // Determine whether all pet names 
                // in the array start with 'B'.
                bool allStartWithB = pets.All(pet =>
                                                  pet.Name.StartsWith("B"));

                Console.WriteLine(
                    "{0} pet names start with 'B'.",
                    allStartWithB ? "All" : "Not all");
            }

            // This code produces the following output:
            //
            //  Not all pet names start with 'B'. 

   List<int> numbers = new List<int> { 1, 2 };
                bool hasElements = numbers.Any();

                Console.WriteLine("The list {0} empty.",
                    hasElements ? "is not" : "is");
 Clump<string> fruitClump =
                new Clump<string> { "apple", "passionfruit", "banana", 
                    "mango", "orange", "blueberry", "grape", "strawberry" };
IEnumerable<string> query2 =
                fruitClump.AsEnumerable().Where(fruit => fruit.Contains("o"));

List<int> grades = new List<int> { 78, 92, 100, 37, 81 };
double average = grades.Average();
            public static void OrderByEx1()
            {
                Pet[] pets = { new Pet { Name="Barley", Age=8 },
                               new Pet { Name="Boots", Age=4 },
                               new Pet { Name="Whiskers", Age=1 } };

                IEnumerable<Pet> query = pets.OrderBy(pet => pet.Age);

            }
            string[] fruits = { "apple", "banana", "mango", "orange", 
                                  "passionfruit", "grape" };

            var query =
                fruits.Select((fruit, index) =>
                                  new { index, str = fruit.Substring(0, index) });

            int[] grades = { 59, 82, 70, 56, 92, 98, 85 };

            IEnumerable<int> lowerGrades =
                grades.OrderByDescending(g => g).Skip(3);

   
            int[] amounts = { 5000, 2500, 9000, 8000, 
                                6500, 4000, 1500, 5500 };

            IEnumerable<int> query =
                amounts.SkipWhile((amount, index) => amount > index * 1000);

            int[] grades = { 59, 82, 70, 56, 92, 98, 85 };

            IEnumerable<int> topThreeGrades =
                grades.OrderByDescending(grade => grade).Take(3);

string[] fruits = { "apple", "passionfruit", "banana", "mango", 
                                  "orange", "blueberry", "grape", "strawberry" };

            IEnumerable<string> query =
                fruits.TakeWhile((fruit, index) => fruit.Length >= index);
string[] fruits = { "grape", "passionfruit", "banana", "mango", 
                                  "orange", "raspberry", "apple", "blueberry" };

            // Sort the strings first by their length and then 
            //alphabetically by passing the identity selector function.
            IEnumerable<string> query =
                fruits.OrderBy(fruit => fruit.Length).ThenBy(fruit => fruit);
  int[] numbers = { 0, 30, 20, 15, 90, 85, 40, 75 };

            IEnumerable<int> query =
                numbers.Where((number, index) => number <= index * 10);

How to: Perform Inner Joins

   http://msdn.microsoft.com/ru-ru/library/bb397941.aspx
class Person
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
        }

        class Pet
        {
            public string Name { get; set; }
            public Person Owner { get; set; }
        }

        /// <summary>
        /// Simple inner join.
        /// </summary>
        public static void InnerJoinExample()
        {
            Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
            Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
            Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
            Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };
            Person rui = new Person { FirstName = "Rui", LastName = "Raposo" };

            Pet barley = new Pet { Name = "Barley", Owner = terry };
            Pet boots = new Pet { Name = "Boots", Owner = terry };
            Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
            Pet bluemoon = new Pet { Name = "Blue Moon", Owner = rui };
            Pet daisy = new Pet { Name = "Daisy", Owner = magnus };

            // Create two lists.
            List<Person> people = new List<Person> { magnus, terry, charlotte, arlene, rui };
            List<Pet> pets = new List<Pet> { barley, boots, whiskers, bluemoon, daisy };

            // Create a collection of person-pet pairs. Each element in the collection
            // is an anonymous type containing both the person's name and their pet's name.
            var query = from person in people
                        join pet in pets on person equals pet.Owner
                        select new { OwnerName = person.FirstName, PetName = pet.Name };

            foreach (var ownerAndPet in query)
            {
                Console.WriteLine("\"{0}\" is owned by {1}", ownerAndPet.PetName, ownerAndPet.OwnerName);
            }
        }

        // This code produces the following output:
        //
        // "Daisy" is owned by Magnus
        // "Barley" is owned by Terry
        // "Boots" is owned by Terry
        // "Whiskers" is owned by Charlotte
        // "Blue Moon" is owned by Rui

How to: Dynamically Specify Predicate Filters at Runtime (C# Programming Guide)

How to: Group Query Results (C# Programming Guide)

http://msdn.microsoft.com/ru-ru/library/bb545974.aspx

public void GroupByRange()
{            
    Console.WriteLine("\r\nGroup by numeric range and project into a new anonymous type:");

    var queryNumericRange =
        from student in students
        let percentile = GetPercentile(student)
        group new { student.FirstName, student.LastName } by percentile into percentGroup
        orderby percentGroup.Key
        select percentGroup;

    // Nested foreach required to iterate over groups and group items.
    foreach (var studentGroup in queryNumericRange)
    {
        Console.WriteLine("Key: {0}", (studentGroup.Key * 10));
        foreach (var item in studentGroup)
        {
            Console.WriteLine("\t{0}, {1}", item.LastName, item.FirstName);
        }
    }            
}

Return a Query from a Method

How to: Query a Collection of Objects

How to: Write LINQ Queries in C#

http://msdn.microsoft.com/ru-ru/library/bb397678.aspx

Method Syntax
List<int> numbers1 = new List<int>() { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
List<int> numbers2 = new List<int>() { 15, 14, 11, 13, 19, 18, 16, 17, 12, 10 };
// Query #4.
double average = numbers1.Average();

// Query #5.
IEnumerable<int> concatenationQuery = numbers1.Concat(numbers2);

IEnumerable<int> largeNumbersQuery = numbers2.Where(c => c > 15);

Query Expression Basics (C# Programming Guide)

http://msdn.microsoft.com/ru-ru/library/bb384065.aspx
IEnumerable<int> highScoresQuery =
    from score in scores
    where score > 80
    orderby score descending
    select score;

Introduction to LINQ Queries

http://msdn.microsoft.com/ru-ru/library/bb397906.aspx

class IntroToLINQ
{        
    static void Main()
    {
        // The Three Parts of a LINQ Query:
        //  1. Data source.
        int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };

        // 2. Query creation.
        // numQuery is an IEnumerable<int>
        var numQuery =
            from num in numbers
            where (num % 2) == 0
            select num;

        // 3. Query execution.
        foreach (int num in numQuery)
        {
            Console.Write("{0,1} ", num);
        }
    }
}

О лямбда-выражениях

Лямбда-выражение — это сокращенный способ объявления простого анонимного метода

public class LambdaTest
{
       static void Main() {
       Func<int, double> expr = x => x / 2;
       int someNumber = 9;
       Console.WriteLine( "Результат: {0}", expr(someNumber) );
 }

            Func<int, int> expr = (x) =>
            {
                x = x * 10;
                MessageBox.Show(x.ToString());
                return x;
            };
            expr(1000);


Фантастические ошибки C++


Найди страшную ошибку в программе C++


четверг, 19 июня 2014 г.

Пишем систему автоматизированных тестов "с нуля"

http://www.protesting.ru/automation/practice/automation_from_scratch.html

1. Определяем требования к системе автоматизированного тестирования
2. Определение компонентов системы.

Автоматический инсталлятор приложения, а также сопутствующая ему функциональность для получения новой версии из репозитория, ftp, либо другого места куда автоматически выкладываются сборки поможет вам избежать выполнения всех этих действий вручную, а значит – освободит время на другие задачи.

Автоматизированные тесты (скрипты + фреймворк для их выполнения). Этот компонент включает всю инфраструктуру тестов - компоненты для работы с удаленной и локальной файловой системой, сервисами/демонами, фреймворк для работы с формами приложения и, собственно, сами тест-скрипты.

Автоматический деинсталлятор приложения. Его лучше будет вызывать перед инсталляцией новой версии. Это также освобождает время на другие задачи. Вместо него можно использовать полное восстановление системы (например, из полного бэкапа диска).

Автоматизированная система восстановления рабочей среды.

Автоматизированная система хранения результатов автоматических тестов. Для построения графиков ретроспективы, выявления ошибок в тестах, оценки динамики роста/падения качества приложения необходимы не только последние, но и предыдущие результаты автотестов. Лучше хранить их в базе данных, так как она обеспечивает более богатые возможности манипуляции данными.

Автоматизированная система формирования и рассылки результатов тестов.

3. Определение компонентов для разработки
На данном этапе вы уже должны определиться со списком и приоритетами задач по автоматизации и решить, какие задачи решать с помощью готовых компонентов, а что разрабатывать самому.

4. Оценка объемов работы.
После того как выбор компонентов закончен, есть резон потратить некоторое время на осмысление того, что вам предстоит сделать. Естественно, готовые компоненты не нуждаются в оценке. Оценивать нужно работу по их интерграции в вашу систему.

5. Разработка. Практические рекомендации.

5.1 WEB/GUI

1. Выделяем классы форм
2. Выносим общие методы взаимодействия с элементами из классов форм в общий суперкласс
3. Выносим данные теста из скрипта в подгружаемый файл (поддержка Data-Driven testing)
4. Создаем кейворды (поддержка Keyword-Driven testing)

5.2 Файловая система

копирование/создание/удаление/проверка существования файлов
архивация/разархивация файлов и каталогов
копирование файлов с/на целевую файловую систему
поиск в файлах по паттерну (логи) / изменение содержимого текстовых файлов (конфиги)
выполнение команд на удаленной системе и получение стандартного вывода (stdout) и ошибок (errout) от них.

5.3 Сервисы и демоны

Общий алгоритм такой:
1. Проверка состояния.
2. Если сервис/демон уже в нужном состоянии - выход.
3. Если достигнут таймаут запуска/остановки сервиса - выход с ошибкой.
4. Если сервис/демон в промежуточном состоянии (starting|stopping) - ждем таймаут и идем на шаг1.
5. Отдаем команду запуска/остановки сервиса.
6. Проверка состояния.
7. Если сервис/демон в нужном состоянии - выход.
8. Если достигнут таймаут запуска/остановки сервиса - выход с ошибкой.
9. Если сервис/демон в промежуточном состоянии (starting|stopping) - ждем таймаут и идем на шаг6.

5.4 Базы данных

Единый интерфейс для работы с базами данных будет полезен, если тестируемое приложение должно поддерживать работу на нескольких типах баз данных.

5.5 Отчеты

Время начала выполнения теста
Время завершения выполнения теста
Результат (passed / failed / blocked)
Полный лог выполнения теста и крайне желательно - с метками времени для каждой записи в логе
Номер билда для которого проводился тест
Конфигурация (аппаратная платформа + настройки) на которой проводился тест. (Актуально только если используется несколько конфигураций)
Скриншот (в сучае отличного от passed результата)

Еще одна большая тема. Всегда нужно помнить о том что отчеты - это результат вашей работы. 

Selenium training video

Хорошо описана структура фреймворка для тестирования.


среда, 18 июня 2014 г.

Ошибки при автоматизации.


Ошибка №1: Нам нужны автотесты.


Принимать это решение нужно на основе данных о том, насколько часто будет изменяться продукт и требования к этому продукту, или же подвергаемое тестированию решение будет разработано и , скажем, отдано кому-то, и изменений в нем не предвидится в ближайшее(и не очень) время.
Совет 1: всегда, когда вам дают задачу и говорят написать автоматические тесты, сначала проанализируйте, а какова будет их цена в разрезе затраченного времени на разработку и поддержку?
Совет 2: не бойтесь сказать «заказчику» работы, что его слова, что нужно написать автоматические тесты – не правильные, так как автотесты здесь для данного компонента или продукта – не нужны. Проще написать ручные тесты и прогонять их по необходимости, так как на это реально будет потрачено меньше сил и времени.


Ошибка №2: Чрезмерная автоматизация.
Первая - затрачивается много времени на разработку тестов. И, зачастую, все эти тесты написаны не оптимально. Проверено на опыте , полученном в проектах, в которых я работал. Причем, хочется отметить, что специалисты в этих проектах был подобраны достаточно сильные. Вторая - поддержка тестов. Вытекает эта проблема из первой. Чем больше тестов написано - тем больше времени тратится на их поддержку и модификацию. Третья - не всегда оптимально выбран подход к написанию(здесь имеется в виду и архитектура и, например, инструмент, используемый для написания тестов). И всё это приводит к четвертой проблеме - в какой то момент наступает момент, когда начинается безостановочная “борьба за зеленый кружок”. Совет 1: никогда не бойтесь сказать(разумеется приведя грамотные аргументы, базу для которых, например, можно почерпнуть из пары предыдущих абзацев), что “столько” тестов не нужно. Не бойтесь дойти с этими словами до большого руководства. Ведь в реальности, хороший специалист по автоматизации - это не тот, кто может много написать, а кто напишет столько, сколько нужно и может грамотно объяснить, почему именно такое количество - оптимальное и достаточное. Эту мысль я буду упоминать и в дальнейших разделах , потому что она очень и очень важна. Совет 2: всегда с осторожностью и особой вдумчивостью подходите к выбору подхода к автоматизации. Это сэкономит время ваше и ваших коллег как сейчас, так и в будущем.

Ошибка №3: Использование ненужных библиотек.

овет 1: не используйте библиотеки, которые не знаете, как реализованы внутри и, при желании и наличии времени, не можете написать сами. Если вы реально разобрались, что именно этот модуль подходит вам для ваших целей, вы поняли, что он будет использован оптимально(а не его 1-2%), то есть большая часть его функциональности будет вами использована , и для создания собственного решения, реализующего ту же функциональность , вами будет потрачено много времени и строчек кода - тогда берите и используйте. В любом случае - перед тем, как подключать что-то стороннее - подумайте о целесообразности этого решения и подумайте, не проще ли сделать всё своими руками? Это, зачастую, упорщает разрабатываемое решение и делает его более легковесным, и позволяет вам развиваться, как специалисту, изучая различные стандартные, входящие в базовое SDK(я рассматриваю это всё на примере языка Java), библиотеки. Совет 2: старайтесь накапливать как можно больше своих, удобных и проверенных временем разработок и библиотек. Это упростит вам жизнь при написании и поддержке кода и ускорит время, затрачиваемое на поиск нужного вам решения в интернете. Совет 3: не бойтесь тратить время на то, чтобы досканально разобраться в том, что вы используете. Это возможно покажется дубликатом первого совета, но это очень важно понимать.

Ошибка N4: много настроек.
всегда хорошенько продумывайте , как ваши тесты будут настраиваться и старайтесь делать как можно меньше различных параметров.

http://sidelnikovmike.blogspot.ru/2013/03/blog-post.html

среда, 11 июня 2014 г.

Crystal Agile, или как мы приспособили процесс разработки для обеспечения максимального качества

Построение системы нагрузочного тестирования

Исследование багов: учимся у Шерлока Холмса!

Процесс тестирования во многом похож на процесс расследования. Он полон анализа, логических рассуждений, ложных и верных выводов. И самое интересное начинается в момент исследования сложновоспроизводимых багов. Это может быть плавающий баг, точные способы воспроизведения которого мы никак не можем понять. Или обезличенный баг от пользователей , представляющий собой в лучшем случае скриншот с припиской "Помогите! Ничего не работает!!!" В "расследовании" таких и других сложных багов я предлагаю поучиться методам, которые использовал известный всем сыщик Шерлок Холмс. Я расскажу, какие идеи и подходы показались мне применимыми и полезными в тестировании. Они помогут тестировщикам потратить меньше усилий на локализацию ошибки, исследовать проблему с интересом и страстью, и, возможно, когда-нибудь с удовольствием сказать себе "Это элементарно..."

Конструируем тест-план методом Google

Развитие унаследованного фреймворка тестирования

Автоматизация тестирования: отбрасываем лишнее и проверяем суть

Как эффективно организовать автоматизацию

Способы расширения зоны влияния вашей системы автотестов

Антипаттерны поведения и развития тестировщиков - автоматизаторов

О книгах по программированию

словно, книги по программированию, можно разделить на две категории:
1.   Изучение инструмента, языка программирования. Если Вы прочитаете учебник по C#, Java, Python, Perl – то результат будет очевидный. Вы сможете написать первую программу, и узнаете, как можно использовать те или иные технологии.
2.   Вторая категория – это книги для совершенствования Вашего мастерства. Тут Вы изучаете новые подходы, рассматриваете варианты использования тех или иных подходов, взвешиваете все за и против вместе с автором. Это такие книги, как Design Patterns, Code Complete и т.д.

Точно так же и с книгами по автоматизации. Если Вам в данный момент нужно изучить инструмент – берите учебник или руководство по этому инструменту и сопутствующих технологий. Такие примеры содержат простые практические примеры, которые Вы, при желании, можете сразу же реализовать на практике.

Если же вы хотите набраться  опыта  и/или перед Вами стоит задача начала поддержки и развития проектов по автоматизации – то вторая категория для Вас. Обычно в таких книгах авторы делятся своим опытом,  своими лучшими практиками, но, несмотря на это, в таких книгах больше теории.

Книги первой категории устаревают очень быстро. Книги второй – могут оставаться актуальными в течении 10-ти лет.

Тоже самое касается и книг по автоматизации.
Если Вы только осваиваете автоматизацию –  то книги про инструменты – это то что Вам сейчас нужно. Если Вы в автоматизации уже не первый год – то стоит обратить внимание на теорию, вторую категорию.

Recording Hover’s in CodedUITest

http://blogs.msdn.com/b/rituparna/archive/2009/11/23/recording-hover-s-in-codeduitest.aspx

For recordings on WEB Applications  CodedUITest intelligently identifies that an Hover action has been performed on the application and records a Hover-Action on the control on which the Mouse was hovered . This type of auto-generated Hover-Action is referred to as IMPLICIT HOVER. The action such generated was not explicitly performed by the User (however not recording the action would most certainly lead to a faulty recording) and as such is tagged with the ContinueOnError flag. This indicates that even if the action is not played back the Test wont fail and execution will pass on to the next Step. The code generated for Implicit Hovers will look like
// Set flag to allow play back to continue if non-essential actions fail. (For example, if a mouse hover action fails.) 
Playback.PlaybackSettings.ContinueOnError = true;
           // Mouse hover 'My Bay' link at (56, 3) 
           Mouse.Hover(uIMyBayHyperlink, new Point(56, 3));
// Reset flag to ensure that play back stops if there is an error. 
Playback.PlaybackSettings.ContinueOnError = false;

FAQ: Running Coded UI Test on a machine without VS

Another one of commonly asked question is how can I run Coded UI Test (or any other test type) on a machine without installing Visual Studio on it?
 You can install Test Agent – the Test Agent is a light-weight install and it is free if you already have appropriate Visual Studio or Test Profession SKU.

MEMORY LEAK DETECTION

TestApi provides a simple memory-leak-detection mechanism, which takes memory snapshots of an executing process and then processes the snapshots with arbitrarily complex leak-detection algorithms, as the following figure shows.
//
// Taking two memory snapshots of Notepad and comparing them for leaks
//

// Start an instance of Notepad.exe, get its PID, and take a memory snapshot
Process p = Process.Start("notepad.exe");
p.WaitForInputIdle(5000);
int pid = p.Id;
Thread.Sleep(3000);
MemorySnapshot s1 = MemorySnapshot.FromProcess(pid);

//
// Perform operations that may cause a leak...
//
Thread.Sleep(2000);

// Capture a second snapshot
MemorySnapshot s2 = MemorySnapshot.FromProcess(pid);

// Compare the two memory snapshots and generate a diff.
// Then display the diff to the console.
MemorySnapshot diff = s2.CompareTo(s1);

Console.WriteLine("Memory diff for process with pid {0}", pid);
Console.WriteLine("Start time:          {0}", s1.Timestamp);
Console.WriteLine("End time:            {0}", s2.Timestamp);
Console.WriteLine("GDI Object Count:    {0}", diff.GdiObjectCount);
Console.WriteLine("Handle Count:        {0}", diff.HandleCount);
Console.WriteLine("PageFile Bytes:      {0}", diff.PageFileBytes);
Console.WriteLine("PageFile Peak Bytes: {0}", diff.PageFilePeakBytes);
Console.WriteLine("Pool Nonpaged Bytes: {0}", diff.PoolNonpagedBytes);
Console.WriteLine("Pool Paged Bytes:    {0}", diff.PoolPagedBytes);
Console.WriteLine("Thread Count:        {0}", diff.ThreadCount);
Console.WriteLine("User Object Count:   {0}", diff.UserObjectCount);
Console.WriteLine("VM Bytes:            {0}", diff.VirtualMemoryBytes);
Console.WriteLine("VM Private Bytes:    {0}", diff.VirtualMemoryPrivateBytes);
Console.WriteLine("WS Bytes:            {0}", diff.WorkingSetBytes);
Console.WriteLine("WS Peak Bytes:       {0}", diff.WorkingSetPeakBytes);
Console.WriteLine("WS Private Bytes:    {0}", diff.WorkingSetPrivateBytes);

// Close the process.
p.CloseMainWindow();
p.Close();

TestApi - a library of Test APIs

http://testapi.codeplex.com/

TestApi is...

TestApi is a library of test and utility APIs that enables developers and testers to create testing tools and automated tests for .NET and Win32 applications. TestApi provides a set of common test building blocks -- types, data-structures and algorithms -- in a simple, layered, componentized and documented stack.

Get started


The ZIP file contains the DLLs, as well as the samples, source code and documentation. 
You can download the ZIP file, and just use the DLLs.