środa, 24 lipca 2013

[Visual Studio] Unit Testy

Pisząc Unit Testy należy pamiętać o zasadzie 3xA: Arrange Act Assert. Oznacza ona, że metody testujące powinny składać się z pewnego szablonu: na początku przypisujemy zmienne i oczekiwane wyjście, później wykonujemy test, a na końcu sprawdzamy, czy wynik jest poprawny. Wygodnym Frameworkiem do pisania Unit Testów w VS jest NUnitFramework. Instalujemy go za pomocą NuGeta.


Przykładowa metoda do przetestowania:

public class StringHelper
{
    public static int CountLetters(string word, char letter)
    {
        return word.Count(c => c == letter);
    }
}

...i odpowiadający mu UnitTest.

[TestFixture]
public class StringHelperTest
{
    [Test]
    public void CountLettersTest()
    {
        //Arrange
        var @string = "copacabana";
        var letter = 'a';
        int expected = 4;

        //Act
        int current = StringHelper.CountLetters(@string, letter);

        //Assert
        Assert.AreEqual(expected, current);
    }
}

Dla klas i metod obowiązuje pewna konwencja dodawania na końcu nazw słowa Test. Unit Testy można także bez problemu Debugować. Korzystając z dodatku Resharper można uruchamiać pojedyncze testy bezpośrednio w kodzie.


Przydatnymi atrybutami są SetUp i TearDown. Będą to metody wykonywane raz odpowiednio przed i po sesji testów.


[SetUp]
public void Init()
{
    Console.WriteLine("Initializing...");
}

[TearDown]
public void Clean()
{
    Console.WriteLine("Shutting down..."); 
}

Testy można także w razie potrzeby grupować w kategorie, również przez odpowiedni atrybut.

[Test]
[Category("another tests")]
public void CountLettersTest2()
{
    //Arrange
    var @string = "copACABana";
    var letter = 'a';
    int expected = 2;

    //Act
    int current = StringHelper.CountLetters(@string, letter);

    //Assert
    Assert.AreEqual(expected, current);
}

Dzięki temu z poziomu GUI możemy odpalać na przykład tylko testy z danej kategorii.


Ostatnia ciekawa funkcjonalność to timeouty. Możemy ustawić dla danej metody maksymalny czas wykonania poprzez atrybut MaxTime, np. [MaxTime(5000)].

wtorek, 23 lipca 2013

[WPF] Grafika trójwymiarowa

Jedną z ciekawszych funkcjonalności WPF jest wsparcie dla grafiki trójwymiarowej. Funkcjonalności 3D są dostępne zarówno z poziomu XAML jak i kodu proceduralnego. Poniższy kod przedstawia prosty sposób opisu sceny 3D w sposób deklaratywny:


<Window x:Class="_3dGraphics.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Viewport3D>
            <Viewport3D.Camera>
                <OrthographicCamera Position="5,5,5" LookDirection="-1,-1,-1" Width="5"/>
            </Viewport3D.Camera>
            <Viewport3D.Children>
                <ModelVisual3D x:Name="Light">
                    <ModelVisual3D.Content>
                        <AmbientLight/>
                    </ModelVisual3D.Content>
                </ModelVisual3D>
                <ModelVisual3D>
                    <ModelVisual3D.Content>
                        <Model3DGroup x:Name="House">
                            <GeometryModel3D x:Name="Roof">
                                <GeometryModel3D.Material>
                                    <DiffuseMaterial Brush="Blue"/>
                                </GeometryModel3D.Material>
                                <GeometryModel3D.Geometry>
                                    <MeshGeometry3D Positions="-1,1,1 0,2,1 0,2,-1 -1,1,-1 0,2,1 1,1,1
      1,1,-1 0,2,-1"
      TriangleIndices="0 1 2 0 2 3 4 5 6 4 6 7"/>
                                </GeometryModel3D.Geometry>
                            </GeometryModel3D>
                            <GeometryModel3D x:Name="Sides">
                                <GeometryModel3D.Material>
                                    <DiffuseMaterial Brush="Green"/>
                                </GeometryModel3D.Material>
                                <GeometryModel3D.Geometry>
                                    <MeshGeometry3D Positions="-1,1,1 -1,1,-1 -1,-1,-1 -1,-1,1 1,1,-1
       1,1,1 1,-1,1 1,-1,-1"
       TriangleIndices="0 1 2 0 2 3 4 5 6 4 6 7"/>
                                </GeometryModel3D.Geometry>
                            </GeometryModel3D>
                            <GeometryModel3D x:Name="Ends">
                                <GeometryModel3D.Material>
                                    <DiffuseMaterial Brush="Red"/>
                                </GeometryModel3D.Material>
                                <GeometryModel3D.Geometry>
                                    <MeshGeometry3D
       Positions="-0.25,0,1 -1,1,1 -1,-1,1 -0.25,-1,1 -0.25,0,1
       -1,-1,1 0.25,0,1 1,-1,1 1,1,1 0.25,0,1 0.25,-1,1 1,-1,1
       1,1,1 0,2,1 -1,1,1 -1,1,1 -0.25,0,1 0.25,0,1 1,1,1 1,1,-1
       1,-1,-1 -1,-1,-1 -1,1,-1 1,1,-1 -1,1,-1 0,2,-1"
       TriangleIndices="0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 15
       17 18 19 20 21 19 21 22 23 24 25"/>
                                </GeometryModel3D.Geometry>
                            </GeometryModel3D>
                        </Model3DGroup>
                    </ModelVisual3D.Content>
                </ModelVisual3D>
            </Viewport3D.Children>
        </Viewport3D>
    </Grid>
</Window>

Zastosowane powyżej elementy XAML służą do:

  • GeometryModel3D - reprezentuje kształt i materiał obiektu 3D, kształt w powyższym przypadku jest siatką, w której podaje się współrzędne trójkątów oraz ich indeksy.
  • ModelVisual3D - odpowiada za renderowanie contentu 3D
Położenie kamery oraz obiektów na scenie podaje się, pamiętając o układzie osi w kartezjańskim układzie współrzędnych.
Układ współrzędnych jest prawoskrętny, a pozycję podaje się ustawiając wartości na atrybucie Position.
Pozostałe ważne atrybuty to LookDirection (kierunek, w którym ma być obrócona kamera), oraz UpDirection decydujący o obrocie kamery wokół osi z. 

Rodzaje kamer:
  • PerspectiveCamera - odpowiada postrzeganiu przestrzeni przez ludzkie oko, obiekty znajdujące się daleko od kamery wydają się mniejsze, niż te bliższe
  • OrthographicCamera - obiekty pozostają tej samej wielkości niezależnie od odległości
Szerokość pola widzenia kontrolowana jest przez atrybut Width (dla drugiej kamery) i przez atrybut FieldOfView (dla pierwszej kamery).

Transformacje 3D:

Poniżej przedstawiono, jak wykonać trzy podstawowe transformacje z poziomu kodu proceduralnego


private void KeyDownHandler(object sender, KeyEventArgs e)
{
    Transform3DGroup group = new Transform3DGroup();
    switch (e.Key)
    {
        case Key.T:
            TranslateTransform3D transform3D = new TranslateTransform3D(0.1,0,0);
            group.Children.Add(transform3D);
            House.Transform = group;
            break;
        case Key.R:
            //45 - stopnie, nie radiany, new Vector3D(0, 1, 0) - wokol jakiej osi obrot
            RotateTransform3D rotate3d = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 45));
            group.Children.Add(rotate3d);
            House.Transform = group;
            break;
        case Key.S:
            ScaleTransform3D scale3d = new ScaleTransform3D(0.5,0.5,1);
            group.Children.Add(scale3d);
            House.Transform = group;
            break;
        default:
            break;
    }
}

Rodzaje świateł:

  • DirectionalLight - wysyła równoległe wiązki światła ze źródła umieszczonego nieskończenie daleko, odpowiada słońcu
  • PointLight - odpowiada żarówce, wysyła światło we wszystkich kierunkach, intensywność spada wraz ze wzrostem odległości od źródła
  • FlashLight - odpowiada działaniu latarki, emituje stożek światła, którego intensywność spada wraz ze wzrostem odległości od źródła
  • AmbientLight - światło rozproszone

sobota, 29 czerwca 2013

[Matlab] Operacje na wektorach i macierzach

Matlab jako jedno z najlepszych narzędzi do obliczeń inżynierskich oferuje sporo przydatnych funkcji do operacji na maciezach i wektorach. Oto niektóre z nich:
  • transpozycja (' lub funkcja transpose)
>> a = [1 2 3 4];
>> a'

ans =

     1
     2
     3
     4

>> transpose(a)

ans =

     1
     2
     3
     4
  • konkatenacja []
>> [a 1 2 3]

ans =

     1     2     3     4     1     2     3
  • podzbiór ()
>> a(2:3)

ans =

     2     3
  • linspace(elementy równomiernie rozłożone pomiędzy dwoma wartościami, pierwsze dwa argumenty to zakres, trzeci to ilość elementów)
>> linspace(0,5,6)

ans =

     0     1     2     3     4     5
  • suma kumulatywna (do każdego elementu dodawana jest suma poprzednich elementów)
>> cumsum(a)

ans =

     1     3     6    10
  • diff (różnica pomiędzy kolejnymi elementami, zwraca wektor o 1 element mniejszy od wektora wejściowego)
>> diff(a)

ans =

     1     1     1
  • podzbiór warunkowy
>> a(a>2)

ans =

     3     4
  • unique (zwraca posortowane unikatowe elementy)
>> unique([a 6 4 5])

ans =

     1     2     3     4     5     6
  • any (zwraca 0 lub jeden w zależności od tego, czy warunek jest spełniony)
>> any(a == 2)

ans =

     1

>> any(a == 0)

ans =

     0
  • find (zwraca indeksy spełniające dany warunek)
>> b = [4 3 0 1];
>> find (b==3)

ans =

     2
  • macierz jednostkowa
>> eye(3)

ans =

     1     0     0
     0     1     0
     0     0     1
  • transformacja macierz - wektor - operator (:)
>> g = eye(3);
>> g(:)

ans =

     1
     0
     0
     0
     1
     0
     0
     0
     1
  • wybór wiersza / kolumny
>> g(3,:)

ans =

     0     0     1

>> g(:,3)

ans =

     0
     0
     1

piątek, 12 kwietnia 2013

[IoC] Ninject

Ostatni post, dotyczący kontenerów IoC pokazuje możliwości Ninjecta. Jest to stosunkowo nowy (2007), darmowy kontener. W celu dodania go do projektu w Visual Studio korzystamy z NuGeta.



Pracę z kontenerem pokazano poniżej:

using (var ninjectContainer = new StandardKernel())
{
    ninjectContainer.Bind<IEngine>().To<GasEngine>();
    var car4 = ninjectContainer.Get<AudiA4>();
    car4.Run();
}

Podobnie jak w większości przypadków nie musimy rejestrować wszystkich typów (tych, o które nie prosimy przez interfejs). Poniżej kilka innych ciekawych funkcjonalności:

public class AudiA4Module : NinjectModule
{
    public override void Load()
    {
        Kernel.Bind<IEngine>().To<DieselEngine>().InSingletonScope();
        Kernel.Rebind<IEngine>()
            .ToMethod(context =>
                                {
                                    var rnd = new Random();
                                    var num = rnd.Next()%2;
                                    if (num == 1)
                                        return new GasEngine();
                                    else
                                        return new DieselEngine();
                                });
    }
}


using (var ninjectContainer = new StandardKernel(new AudiA4Module()))
{
    var car5 = ninjectContainer.Get<AudiA4>();
    car5.Run();
}

Moduły wspierają separację kodu konfigurującego. Nie musimy bindować koniecznie do typu, możemy dokonać bindingu do metody, gdzie wykonujemy jakąś logikę. Ponadto warto pamiętać, że domyślnie zwrócony zostanie zawsze nowy obiekt. Możemy to zmienić, wywołując na przykład metodę InSingletonScope (dla singletonów). Co więcej binding można odwołać metodą Rebind.

[IoC] StructureMap

Kolejnym ciekawym kontenerem IoC, po Unity i Castle of Windsor, jest StructureMap. API wszystkich trzech jest bardzo podobne, choć StructureMap rozwijany jest od 2004 roku i początkowo korzystało się z niego w zupełnie inny sposób. W celu dodania go do projektu w Visual Studio korzystamy z NuGeta.


Aby wykorzystać StructureMap, musimy pamiętać, aby używać .NET Framework 4.0 w wersji pełnej (nie zadziała wersja Client Profile. Pracę z kontenerem pokazano poniżej:

using(var structureMapContainer = new Container())
{
    structureMapContainer.Configure(x => x.For<IEngine>().Use<GasEngine>());
    var car3 = structureMapContainer.GetInstance<AudiA4>();
    car3.Run();
}

Konfiguracja odbywa się przez lambda expressions, nie musimy rejestrować wszystkich typów (tych, o które nie prosimy przez interfejs). Poniżej kilka innych użytecznych funkcjonalności:

public class AudiA4Registry : Registry
{
    public AudiA4Registry()
    {
        For<IEngine>().LifecycleIs(new SingletonLifecycle()).Use<DieselEngine>();
    }


using (var structureMapContainer = new Container(new AudiA4Registry()))
{
    var car3 = structureMapContainer.TryGetInstance<AudiA4>();
    if(car3 != null)
        car3.Run();
}

Rejestry pozwalają na odseparowanie kodu konfigurującego kontener. Metoda TryGetInstance zwróci w przypadku powyższego kodu null, ponieważ typ nie jest jawnie zarejestrowany.

wtorek, 9 kwietnia 2013

[IoC] Castle Windsor

Obok Unity, drugim interesującym kontenerem IoC jest Castle Windsor. Oba kontenery udostępniają całkiem podobne API, warto jednak znać podstawowe różnice. Castle Windsor jest open - sourcowym projektem, jednym z pierwszych .NET-owych kontenerów IoC.W celu dodania go do projektu w Visual Studio korzystamy z NuGeta.


Podstawową przewagą nad Unity jest możliwość stworzenia własnych instalatorów - obiektów implementujących interfejs IWindsorInstaller. W instalatorze takim możemy skonfigurować część zależności. Podczas tworzenia kontenera mamy możliwość dodania wielu instalatorów.


public class AudiA4Installer : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Component.For<AudiA4>().LifeStyle.Transient);
        container.Register(Component.For<IEngine>()
            .ImplementedBy<DieselEngine>().LifeStyle.Transient);
    }
}

Różnice w stosunku do Unity są dwie: musimy rejestrować typy o które prosimy bezpośrednio (nie przez interfejs), domyślny cykl życia obiektu to Singleton, dlatego konieczne jest ustawienie Transient - tworzenie nowej instancji przy każdym Resolve.

using (var windsorContainer = new WindsorContainer())
{
    windsorContainer.Install(new AudiA4Installer());
    var car2 = windsorContainer.Resolve<AudiA4>();
    car2.Run();
}

Castle Windsor wstrzykuje zarówno przez konstruktor jak i przez setter, tak więc klasa wyższego poziomu może być skonstruowana na dwa sposoby.

niedziela, 7 kwietnia 2013

[IoC] Unity

Unity jest kontenerem IoC dostarczanym przez firmę Microsoft. Można go spotkać, jako część biblioteki Enterprise Library, lub pograć managerem pakietów NuGet.


Do projektu dodajemy poniższą referencję:

using Microsoft.Practices.Unity;

Przykład użycia kontenera Unity:

using (var unityContainer = new UnityContainer())
{
    unityContainer.RegisterType<IEngine, DieselEngine>();
    //Setter Injection
    unityContainer.RegisterType<IEngine, DieselEngine>(new InjectionProperty("Power", "100"));
    var car2 = unityContainer.Resolve<AudiA4>();
    car2.Run();
}

Z przykładu tego wynikają dwa fakty. Po pierwsze, jeżeli chcemy dostać typ i prosimy o niego metodą Resolve, a jako parametr generyczny podajemy typ, a nie interfejs, to nie musimy takiego typu rejestrować. Po drugie możemy wstrzykiwać także pojedyncze propercje poprzez klasę InjectionProperty.

Jeżeli chcemy zarejestrować jakiś obiekt, jako singleton, to podajemy przez parametr sposób, w jaki kontener ma zarządzać takim obiektem. Domyślnie mamy typ TransientLifetimeManager, który za każdym razem tworzy nową instancję. Dla singletonów wybieramy ContainerControlledLifetimeManager.

using (var unityContainer = new UnityContainer())
{
    //Singleton
    unityContainer.RegisterType<IEngine, GasEngine>(new ContainerControlledLifetimeManager());
    var car2 = unityContainer.Resolve<AudiA4>();
    car2.Run();
}

Widzimy, że za Unity przemawia proste API zaspokajające podstawowe potrzeby przy wstrzykiwaniu zależności.