Как стать автором
Поиск
Написать публикацию
Обновить

Auto Debug Tool

Время на прочтение4 мин
Количество просмотров567
Итак, представим себе ситуацию. Мы написали программу, отправили ее на тестирование, тестировщик находит ошибку. Его действия – создает письмо, описыват эту ошибку, описывает шаги для воспроизведения, делает скриншот, прикрепляет скриншот к письму, отправляет вам.

Давайте облегчим его труд.

Для этого нам понадобится класс HotKey, который будет перехватывать нажатие горячих клавиш и производить шаманство, класс-обертку MAPI, которая будет сразу вызывать окно с новым письмом мне, и сам класс DebugTool, который соберет всю информацию воедино и выполнит работу.


Класс HotKey использует библиотеку user32.dll для регистрации события на определенное сочетания клавиш (метод RegisterHotKey), если такое сочетание клавиш уже зарегистрировано, то выпадет исключение ApplicationException(«Hotkey already in use»).

В программе регистрируем событие на Ctrl-Shift-B событие OnBugHandle:

public static HotKey hotKey = new HotKey(Keys.B, HotKey.KeyModifiers.Control | HotKey.KeyModifiers.Shift, new EventHandler(OnBugHandle));

где OnBugHandle вызывает статический метод DebugTool.ProcessBug():

public static void OnBugHandle(object obj, EventArgs args)
{
DebugTool.ProcessBug();
}

Далее перейдем к классу-обертке MAPI. Этот класс позволит нам формировать письмо для отправки разработчику:

Теперь перейдем к основному классу DebugTool. Этот класс должен делать следующее:

  • Снять скриншот и записать в файл
  • Скопировать файлы логов
  • Запаковать в архив
  • Создать письмо
  • Прикрепить архив к письму


Кроме того, назначим DebugTool обрабатывать событие OnUnhandledException с записью в отдельный файл стека вызовов и самого исключения.

Создание скриншота:
private static void MakeScreenshot()
{
Bitmap Bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height,
PixelFormat.Format32bppArgb);
Graphics Graphic = Graphics.FromImage(Bitmap);
Graphic.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
Screen.PrimaryScreen.Bounds.Y,
0, 0,
Screen.PrimaryScreen.Bounds.Size,
CopyPixelOperation.SourceCopy);
Bitmap.Save(tempPath + "screenshot.bmp");
}


TempPath — это временная папка, ее можно запросить через Path.GetTempPath(). Туда мы и будем собирать все файлы которые нам необходимо заархивировать.

Сохранение в файл стека вызовов:

private static void SaveStack()
{
using (TextWriter textWriter = new StreamWriter(
new FileStream(tempPath + "stack.txt", FileMode.Create, FileAccess.Write),
Encoding.Unicode))
{

StackTrace st = new StackTrace(true);
for (int i = 0; i < st.FrameCount; i++)
{
StackFrame sf = st.GetFrame(i);
textWriter.WriteLine(string.Empty);
textWriter.WriteLine("Method: {0}", sf.GetMethod());
textWriter.WriteLine("Line Number: {0}", sf.GetFileLineNumber());
}
}
}

Сохранение данных об исключении (с рекурсивной записью всех внутренних исключений):

private static void ExceptionInfo(Exception ex)
{
Exception currentException = ex;
using (TextWriter textWriter = new StreamWriter(
new FileStream(tempPath + "exception.txt", FileMode.Create, FileAccess.Write),
Encoding.Unicode))
{

while (currentException != null)
{
textWriter.WriteLine(string.Empty);
textWriter.WriteLine("Message : " + currentException.Message);
textWriter.WriteLine("Stack Trace : " + currentException.StackTrace);
textWriter.WriteLine("Source : " + currentException.Source);
currentException = currentException.InnerException;
}
}
}

Теперь сама обработка ошибки. Тут мы вначале делаем скриншот, потом копируем все прикрепленные файлы во временную папку. Создаем zip-архив с помощью ZipPackage, и посылаем этот архив:

public static void ProcessBug()
{
List files = new List();
tempPath = Path.GetTempPath();
MakeScreenshot();

foreach (string BindFile in BindedFiles)
{
if (File.Exists(BindFile))
{
File.Copy(BindFile, tempPath + Path.GetFileName(BindFile), false);
files.Add(Path.GetFileName(BindFile));
}
}

files.Add(Path.GetFileName("screenshot.bmp"));
using (Package package = ZipPackage.Open(tempPath + "package.zip", FileMode.Create))
{
foreach (string fi in files)
{
Uri partUri = PackUriHelper.CreatePartUri(new Uri(fi, UriKind.Relative));
PackagePart packagePart = package.CreatePart(partUri, MediaTypeNames.Text.Plain);

using (FileStream fileStream = new FileStream(tempPath + fi, FileMode.Open, FileAccess.Read))
{
CopyStream(fileStream, packagePart.GetStream());
}
}
package.Flush();
}

SendPackage(BugMessageSubject, tempPath + "package.zip");

foreach (string fi in files)
{
File.Delete(tempPath + fi);
}
File.Delete(tempPath + "package.zip");
}


Метод SendPackage попытается вызвать окно с новым письмом, но в случае ошибки скопирует наш zip-архив на рабочий стол:

private static void SendPackage(string MessageSubject, string packageFile)
{
try
{
MAPI mapi = new MAPI();
mapi.AddRecipientTo(MessageTo);
mapi.AddAttachment(packageFile);
int sendResult = mapi.SendMailPopup(MessageSubject, MessageBody);
if (sendResult > 1)
{
string DesktopFolder = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
File.Copy(packageFile, DesktopFolder + "\\bug_" + Path.GetFileNameWithoutExtension(packageFile)
+ "_" + DateTime.Now.ToString("yyyyMMddHHmm") + Path.GetExtension(packageFile), true);
MessageBox.Show("I'd copyed package.zip into desktop. Send it.");
}
}
catch (Exception ex)
{
MessageBox.Show("Can't process. Exception :" + ex.Message);
}
}


Примерно такой же будет обработка и OnUnhandledException.

Теперь проинициализируем наш класс для работы:
static void Main()
{
...
//Обработка UnhandledException
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(ProcessUnhandledException);
//Прикрепим файлы протоколирования
DebugTool.BindedFiles.Add(“logs.log”);
//проинициализируем оправку для MAPI
DebugTool.MessageTo = "...@gmail.com";
DebugTool.UnhandledMessageSubject = "Unhandled exception in your application";
DebugTool.BugMessageSubject = "Bug in application";
DebugTool.MessageBody = "<Please, leave here your comment>";
}

private static void ProcessUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
DebugTool.ProcessUnhandledException(e);
}


Всё! Теперь тестеру нужно сказать, что при нажатии на Ctrl-Shift-B он может моментально уведомить нас об ошибке.

Скачать файлы
Теги:
Хабы:
Всего голосов 9: ↑5 и ↓4+1
Комментарии2

Публикации

Ближайшие события