03/02/2009

Zakamarki Visual Studio (cz. 3)

Home

W trzecim już poście dotyczącym zakamarków Visual Studio, czyli mało znanych funkcji tego środowiska programistycznego, chciałbym napisać o oknie Object Test Bench. Okno to pozwala na szybkie testowanie wywołań metod statycznych i instancyjnych bez potrzeby pisania małych programików testowych. Jeśli po uruchomieniu środowiska nie jest widoczne możemy je wyświetlić wybierając View->Other Widnows->Object Test Bench. Aby wygodnie pracować z tym oknem przyda się również okno Class View (View->Class View), które służy do przeglądania typów zdefiniowanych w naszych projektach oraz w innych pakietach/podzespołach (ang. assembly), do których się odwołujemy. Ważna uwaga! Widok Object Test Bench może zostać użyty tylko i wyłącznie do testowania klas w projekcie oznaczonym jako StartUp oraz w pakietach, do których ten projekt się odwołuje. Co prawda zgodnie z dokumentacją powinniśmy móc testować wszystkie klasy w bieżącym rozwiązaniu (ang. solution) ale niestety nie jest to możliwe.

Dalej będę posługiwał się prościutką, a wręcz naiwną klasą zdefiniowaną poniżej, w celu omówienia zastosowania okna Object Test Bench.
public class Person
{
 private static int count = 0;
 
 private string name;
 private DateTime dateOfBirth;

 public string Name
 {
  get { return name; }
  set { name = value; }
 }

 public DateTime DateOfBirth
 {
  get { return dateOfBirth; }
  set { dateOfBirth = value; }
 }

 public Person()
 {
  Person.count++;
 }

 public Person(string name, DateTime dateOfBirth)
 : this()
 {
  this.name = name;
  this.dateOfBirth = dateOfBirth;
 }

 public int GetAge(bool inDays)
 {
  if(!inDays)
   return DateTime.Now.Year - dateOfBirth.Year;
  else
   return (DateTime.Now - dateOfBirth).Days ;
 }

 public static int GetCount()
 {
  return Person.count;
 }
}
Aby rozpocząć testowanie jakiejś klasy musimy zlokalizować ją w oknie Class View i wywołać dla niej menu kontekstowe. W menu kontekstowym powinny być widoczne dwie komendy:
  • Create Instance - Pozwala wywołać dowolny konstruktor dla danego typu i przypisać mu identyfikator. Stworzony obiekt pojawi się w oknie Object Test Bench. Dla stworzonych obiektów możemy następnie wywoływać metody instancyjne. W ten sposób nie powołamy do życia instancji klasy abstrakcyjnej czy też delegata.
  • Invoke Static Mehtod - Pozwala wywołać wybraną metodę statyczną danej klasy (również klasy abstrakcyjnej).
Polecenia te będą widoczne tylko dla klas z projektu głównego. Oczywiście przed wywołaniem metody statycznej, instancyjnej czy też konstruktora powinniśmy w interesujących nas miejscach w kodzie ustawić breakpointy.

Zacznijmy od wywołania metody statycznej. Po najechaniu w menu kontekstowym na polecenie Invoke Static Mehtod wyświetlone zostaną wszystkie metody statyczne dostępne w tej klasie. Należy wybrać jedną z nich. W przypadku naszej klasy testowej Person możemy wybierać pomiędzy GetCount() oraz dwie metodami odziedziczonymi po klasie Object: Equals(object, object) oraz ReferenceEquals(object, object). Po wybraniu GetCount() pojawi się okno potwierdzające chęć wywołania tej metody. Natomiast w przypadku metod, które posiadają parametry pojawi się okno pozwalające na wyspecyfikowanie wartości tych parametrów. Kiedy klikniemy Ok metoda zostanie wywołana. Na zakończenie pojawi się okno z wynikiem, które powinno wyglądać jak poniżej: Istnieje również możliwość zapisania wyniku wywołania metody. W tym celu powinniśmy zaznaczyć opcję Save return value (w oknie pokazanym powyżej) i nadać identyfikator dla zwracanego obiektu/struktury. Jeśli zdecydujemy się na zapisanie wyniku pojawi się on w oknie Object Test Bench: Stworzone obiekty reprezentowane są w oknie Object Test Bench przez prostokąty. Dla każdego obiektu możemy wywołać menu kontekstowe, które pozwoli nam wybrać metodę instancyjną do wywołania. Spróbujmy wykonać metodę posiadającą parametry np.: CompareTo(int). Po jej wybraniu powinniśmy zobaczyć okno jak poniżej: Warto zauważyć, że jeżeli metoda opatrzona była komentarze to zostanie on przytoczony. Po podaniu wartości parametru aktualnego i wybraniu przycisku Ok, metoda zostanie wywołana, a wynik zostanie przedstawiony w takim samym oknie jak przy wywoływaniu metody statycznej (jego też możemy zapisać).

Przyjrzyjmy się teraz poleceniu Create Instance i stwórzmy instancję klasy Person korzystając z konstruktora dwuargumentowego. Po wybraniu konstruktora powinno pojawić się okno przedstawionej dalej: Po pierwsze powinniśmy podać nazwę dla tworzonego obiektu. W tym miejscu trzeba uważać bo jeśli podanym nazwę, której już użyliśmy zostaniemy o tym poinformowani dopiero po naciśnięciu przycisku Ok, a nie ma możliwości cofnięcia się i naprawienia błędu.

Po drugie, podobnie jak przy wywoływaniu metod, należy podać wartości poszczególnych argumentów. Napiszę o tym troszeczkę więcej. Jeśli chodzi o typy proste nie ma co się rozpisywać. Po prostu wpisujemy liczbę lub ciąg znaków (zamknięty w cudzysłowy) i koniec. Troszeczkę trudniej jest z typami złożonymi. Na rysunku widać, że dla parametru dateOfBirth wstawiłem dziwną wartość dateTime1. Niestety ale w przypadku typów złożonych musimy najpierw stworzyć instancję danego typu, a dopiero potem powołując się na przypisaną danej instancji nazwę, użyć jej jako argumentu wywołania. Nazwa stworzonej instancji pojawi się na rozwijanej liście dla argumentów o odpowiednim typie.

W tym przypadku stworzyłem uprzednio strukturę typu DateTime i nadałem jej nazwę dateTime1. Zacząłem od zlokalizowania typu struktury w drzewie (najwygodniej posłużyć się przyciskiem Search u góry okna Class View). Następnie wybrałem polecenie Create Instance, dalej zdecydowałem się na konstruktor trójargumentowy, jako argumenty wywołania podając rok, miesiąc i dzień mojego urodzenia (wszystkie wartości to typy proste). Na koniec powróciłem do klasy Person i ponownie wybrałem interesujący mnie konstruktor. Jak widać tworzenie obiektów wymagających skomplikowanej inicjalizacji jest trudne i kłopotliwe ale te okno nie do tego służy.

Po stworzeniu instancji klasy Person możemy przystąpić do testowania jej metod, a właściwie jednej metody. Odbywa się to dokładnie w ten sam sposób jak opisałem na przykładzie metody CompareTo(int). Polecam spróbować wywołać metodę GetAge(bool) z parametrem true oraz false oraz sprawdzić jaki wynik zwraca metoda statyczna GetCount() po utworzeniu instancji klasy Person.

Jeszcze dwie uwagi na koniec. Jeśli wprowadzimy jakieś zmiany do kodu to okno Object Test Bench wymusi na nas ponowną kompilację źródeł. Równoznaczne jest to z utratą wszystkich obiektów, struktur, które umieściliśmy wcześniej w tym oknie.

W drugiej części tej serii postów pisałem o oknie Immediate. W ciekawy sposób współpracuje ono z oknem Object Test Bench. Dla przypomnienia w oknie Immediate również możemy wywoływać metody i tworzyć obiekty. Istotne jest to, że obiekty, które stworzymy w tym oknie pojawią się również w oknie Object Test Bench. Tutaj też obowiązuje warunek, żeby użyty typ pochodził z projektu oznaczonego jako StartUp lub z pakietu/podzespołu, do którego tej projekt się odwołuje. Kolejny warunek jaki musimy spełnić (wygląda to na błąd w Visual Studio) jest taki, że okno Object Test Bench nie może być puste w momencie tworzenia obiektu w oknie Immediate. Jeśli będzie tworzone obiekty nie zostaną do niego dodane. Co ciekawe jeśli w pewnym momencie dodamy jakiś obiekt do okna Object Test Bench (z poziomu okna Class View) to nagle pojawią się w nim również obiekty utworzone wcześniej w oknie Immediate.

Warto jeszcze dodać, że obiekty z okna Immediate w oknie Object Test Bench będą miały takie same identyfikatory jak zmienne użyta w oknie Immediate. Czyli wpisanie takiej komendy:
Person person = new Person();
spowoduje dodanie do okna Object Test Bench obiektu o nazwie person

Opisane techniki testowałem w środowiskach Visual Studio 2005 oraz Visual Studio 2008.

0 comments:

Post a Comment