wtorek, 22 listopada 2011

Inversion of Control/Dependency Injection & StructureMap cz.2

Wyobraźmy sobie sytuację w której mamy jakąś aplikację, która jest internetowym sklepem. W
aplikacji takiej powinniśmy móc dodać coś do koszyka zakupowego i oczywiście zobaczyć w każdej chwili co znajduje się w naszym koszyku.
   public class ShoppingCartController
{
private ShoppingCartService _shoppingCartService;

public ShoppingCartController()
{
_shoppingCartService = new ShoppingCartService();
}

public ShoppingCart GetCart()
{
ShoppingCart cart = _shoppingCartService.GetContents();
return cart;
}

public ShoppingCart AddItemToCart(int itemId, int quantity)
{
ShoppingCart cart = _shoppingCartService.AddItemToCart(itemId, quantity);
return cart;
}
}
Zakładamy że za pomocą klasy ShoppingCartService aplikacja łączy się z jakąś usługą. Przestowanie tego kawałka kodu polegałoby na napisaniu metody testującej w której wywołujemy po prostu metody powyższej klasy. Załóżmy teraz, że chcelibyśmy napisać testy, które nie będą łączyć się z usługą. Co trzeba by było zrobić. Najprostszym sposobem jest stworzenie fake klasy ShoppingCartService nazwijmy ją ShoppingCartServiceFake. Zmodyfikujmy kod aby zadanie to było możliwe do wykonania. Na początku, stwórzmy interfejs IShoppingCartService i zmodyfikujmy nieco kod tak jak poniżej:
    public interface IShoppingCartService
{
ShoppingCart GetContents();
ShoppingCart AddItemToCart(int itemId, int quantity);
}

public class ShoppingCartController
{
private IShoppingCartService _shoppingCartService;
public ShoppingCartController()
{
_shoppingCartService = new ShoppingCartService();
}

public ShoppingCart GetCart()
{
ShoppingCart cart = _shoppingCartService.GetContents();
return cart;
}

public ShoppingCart AddItemToCart(int itemId, int quantity)
{
ShoppingCart cart = _shoppingCartService.AddItemToCart(itemId, quantity);
return cart;
}

}
Zakładamy teraz że ShoppingCartService implementuje interface IShoppingCartService. Teraz
dopismy klasę fake


Ostatnim elementem jest dopisanie nowego konstruktora do klasy ShoppingCartController:

public ShoppingCartController(IShoppingCartService shoppingCartService)

{

_shoppingCartService = shoppingCartService;

}

Teraz możemy napisać test:

[TestClass]

public class ShoppingCartControllerTests

{

[TestMethod]

public void GetCartSmokeTest()

{

ShoppingCartController controller =

new ShoppingCartController(new ShoppingCartServiceFake());

ActionResult result = controller.GetCart();

Assert... //sprawdzamy sobie tutaj jakiś warunek np. ilośc itemów

}

}

Jak widać na potrzeby testu jednostkowego tworzymy instancję obiektu ShoppingCartController z
fałszywym obiektem, który udaje klasę łączącą się z usługą.

Teraz załóżmy sytuację taką w której chcielibyśmy móc w jednym miejscu skonfigurować, która klasa
– czy ta która się łączy z usługą czy fałszywa – jest podawana do konstruktora:

public ShoppingCartController(IShoppingCartService shoppingCartService)

{

_shoppingCartService = shoppingCartService;

}

I z pomocą tutaj przychodzi nam StructureMap. Dll można pobrać ze strony: https://github.com/
structuremap/structuremap/downloads. Po pobraniu wystarczy dodać referencję do pliku
StructureMap.dll.

Teraz mając konstruktor przedstawiony powyżej piszemy nowy bezparametrowy

public ShoppingCartController() : this(ObjectFactory.GetInstance<
IshoppingCartService>

{

_shoppingCartService = shoppingCartService;

}

Teraz aby ObjectFaktory zwrócił nam odpowiedni obiekt klasy musimy napisać BootStrapper –
specjalną klasę, która odpowiednio skonfiguruje nam StructureMap:

public class DependencyRegistry : Registry

{

public DependencyRegistry()

{

For().Use();

//Lub jeśli będziemy chceli używać klasy, która naprawdę łączy
się z usługą: For().Use();

}

}

public static class BootStrapper

{

public static void Bootstrap()

{

);

}

}

ObjectFactory.Initialize(x => x.AddRegistry(new DependencyRegistry())

Teraz w metodzie main klasy program wpisać: BootStrapper.BootStrap() i podczas wywołania
nowego kontruktora do klasy zostanie przekazany odpowiedni obiekt klasy dziedziczącej po
interfejsie IShoppingCartService

0 komentarze:

Prześlij komentarz

 
Design by Free WordPress Themes | Bloggerized by Lasantha - Premium Blogger Themes | Online Project management