четверг, 23 июля 2009 г.

Юнит тестирование в C# на примере Visual Studio 2008. Unit test in C#.

Как видно из заголовка в данном посте я не буду рассказывать, что такое юнит тестирование и какие подходу к нему могут быть. Вопросы, которые я отражу в других постах будут включать в себя:

  1. Что такое модульное (unit) тестирование и почему его называют тестирование белого или стеклянного ящика?

  2. Можно ли покрыть программу тестами на 100%?

  3. Как оценивают тестовое покрытие? и его достаточность
  4.  
  5. Использование mock объектов  в unit тестирование

И другие вопросы.


И так начнем. Предыстория вопроса следующая, недавно мне поступило задание написать модульный тест для тестирования изменений конфигурации поискового сервера. Писать модульные тест предстояло на незнакомом мне языке c#. Естественно обращение к поисковому серверу шло через сервис в котором вызывался определенный метод для обращения к серверу. Соответственно в итоге модульный тест создавался для сервиса. В качестве среды разработки модульного теста использовалась Visual Studio 2008. В данном примере я приведу простой пример создания модульного теста в среде VS.


И так, запускаем студию и открываем окно

Окно создания нового проекта в visual studio

В котором выбираем C# class library.

Далее пишем исходный код программы.





using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;

namespace Example
{
public class Dosomething //Объявляем класс
{


public string checksrvstatus(string url)
// метод класса возвращающий строку и принимающий на вход строку
{
if (url == "http://testerway.blogspot.com")
{
// В блоке создается запрос к странице веб сервера и далее обрабатывается ответ
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
string statusdes = myHttpWebResponse.StatusDescription;
string server = myHttpWebResponse.Server;
return ("server: " + server + " status: " + statusdes);

}
else
{

return "";

}

}
public void callchecksrv(int k)
//еще одна функция не возвращающая значение и принимающая на вход число.
{
if (k > 0)
{
checksrvstatus("http://microsoft.com");

}


Далее создаем UnitTest. Нажимаем правую кнопку мыши.


контекстное меню создания юнит теста

Появляется диалог
диалог выбора тестируемого класса, метода

В котором выбирается на какой класс, метод создавать юнит тест. Отображаются все классы и методы в рамках проекта. Необходимо выбрать метод checkservstatus. Затем в появившемся окне задаем имя тестового проекта. И в результате формируется следующий код



using Example;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace TextExample
{


///



///This is a test class for DosomethingTest and is intended
///to contain all DosomethingTest Unit Tests
///

[TestClass()]
public class DosomethingTest
{


private TestContext testContextInstance;

///
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///

public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}

#region Additional test attributes
//
//You can use the following additional attributes as you write your tests:
//
//Use ClassInitialize to run code before running the first test in the class
//[ClassInitialize()]
//public static void MyClassInitialize(TestContext testContext)
//{
//}
//
//Use ClassCleanup to run code after all tests in a class have run
//[ClassCleanup()]
//public static void MyClassCleanup()
//{
//}
//
//Use TestInitialize to run code before running each test
//[TestInitialize()]
//public void MyTestInitialize()
//{
//}
//
//Use TestCleanup to run code after each test has run
//[TestCleanup()]
//public void MyTestCleanup()
//{
//}
//
#endregion


///
///A test for checksrvstatus
///

[TestMethod()]
public void checksrvstatusTest()
{
Dosomething target = new Dosomething(); // TODO: Initialize to an appropriate value
string url = string.Empty; // TODO: Initialize to an appropriate value
string expected = string.Empty; // TODO: Initialize to an appropriate value
string actual;
actual = target.checksrvstatus(url);
Assert.AreEqual(expected, actual);
Assert.Inconclusive("Verify the correctness of this test method.");
}
}
}

Как видно из кода создается тестовый класс в котором создается тестовый метод. В тестовом методе создается экземпляр тестируемого класса. И для тестируемого метода уже подготовлены входные параметры. Плюс сформирован асерт на ожидаемый результат и корректность тестового метода. Необходимо немного изменить тестовый класс.
Добавить строчку



using System.Diagnostics; // для вывода текста в debug trace

[TestMethod()]
public void checksrvstatusTest()
{
Dosomething target = new Dosomething(); // TODO: Initialize to an appropriate value
string url = "http://testerway.blogspot.com"; // TODO: Initialize to an appropriate value
Debug.WriteLine("url: " +url);
string expected = "server: GFE/2.0 status: OK"; // TODO: Initialize to an appropriate value
Debug.WriteLine("expected result: " + expected);
string actual;
actual = target.checksrvstatus(url);
Debug.WriteLine("result: " + actual);
Assert.AreEqual(expected, actual);


}

Далее прогоняем тест. И смотрим окно результата прогона теста.

отчет по результату выполнения модульного теста


И так, что же еще полезное есть в студии. Включаем поддержку codecoverage (оценка покрытия тестируемого кода тестом). Выбираем тестируемую тестом библиотеку. В данном случае example.dll.


включение определения покрытия кода модульным тестом


И теперь после прогона теста можно посмотреть следующие

покрытие кода тестом

Далее наблюдаем результат покрытия кода тестом. Также покрытие кода можно посмотреть в самом коде.


выбор отображения покрытия кода тестом в самом коде

отображение покрытия кода тестом в самом коде


Очевидно, что красным выделен не покрытый тестом код. Также в Studio есть возможность управления набором тестов и другие полезные средства. Итог подводить не буду, так как думаю, что еще изучил не все возможности, которые предоставляет VS 2008 для модульного тестирования.
Использование mock объектов в модульном тестировании на C#

3 комментария:

Unknown комментирует...

Полезная статья

Перс комментирует...

Спасибо. Надеюсь в будущем ее расширить.

Enemis комментирует...

интересно написано спасибо.
Исправьте в описание метода ошибку еcли (к<0)>