Pokazywanie postów oznaczonych etykietą open source. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą open source. Pokaż wszystkie posty

czwartek, 2 lipca 2015

Jestem zachwycony Rką

Zacząłem się uczyć Rkę i jestem zachwycony tym językiem (platformą).
Naprawdę fajne rzeczy można zrobić. Np. do symulowania procesu Wienera

D2_Wiener <- function() {
     dev.new(width = 10, height = 4)
     par(mfrow = c(1, 3), oma = c(0, 0, 2, 0))
     for(i in 1:3) {
         W1 <- cumsum(rnorm(100000))
         W2 <- cumsum(rnorm(100000))
         plot(W1,W2, type= "l", ylab = "", xlab = "")
     }
     mtext("2-dimensional Wiener-processes with no correlation",
     outer = TRUE, cex = 1.5, line = -1)
}​


Kiedy będziemy chcieli dodać skorelowane zmienne to wynik symulacji jest poniżej:
Correlated_Wiener <- function(cor) {
     dev.new(width = 10, height = 4)
     par(mfrow = c(1, 3), oma = c(0, 0, 2, 0))
     for(i in 1:3) {
         W1 <- cumsum(rnorm(100000))
         W2 <- cumsum(rnorm(100000))
         W3 <- cor * W1 + sqrt(1 - cor^2) * W2
         plot(W1, W3, type= "l", ylab = "", xlab = "")
     }
     mtext(paste("2-dimensional Wiener-processes (",cor," correlation)",
     sep = ""), outer = TRUE, cex = 1.5, line = -1)
}




Poniżej zamieszkam ściągi do Rki:

niedziela, 27 października 2013

Korniszonek w BDD

Wymagania szczegółowe aplikacji można zapisać w języku Gherkin. Język ten składa się z 5 słów kluczowych (Given, When, Then, And, But).
Poniżej jest przykład użycia tego języka:

Scenario 1: Zwrot zepsutych butów do magazynu w sklepie
GIVEN: klient kupił buty z naszego sklepu
AND: buty przepuszczają wodę w deszczowe dni
BUT: data zakupu nie starsza niż rok
WHEN: klient zwraca buty,
THEN: buty powinny być w magazynie


Scenario 2: Zakup pasty do butów o 50% taniej przy zakupie butów
GIVEN: klient kupił buty
WHEN: klient chce kupić pastę do butów
THEN: cena pasty do butów o 50% taniej


Są to proste przykłady zastosowania języka Gherkin, które przedstawiają różne zachowania aplikacji.
Więcej można poczytać w książce The Cucumber Book: Behaviour-Driven Development for Testers and Developers oraz na stronie jednego z projektów BDD dla języka php.

W tematyce BDD i Gherkin jestem świeżakiem, ale uważam, że warto zainteresować się tym językiem, gdyż nie wymaga umiejętności programistycznych ze strony testera, PM czy BA, aby napisać przypadek użycia. Książkę jeszcze nie przeczytałem, ale w wolnej chwili muszę się zabrać za nią :)

poniedziałek, 21 października 2013

Kolekcja danych testowych

Jakiś czas temu pisałem o TestCase w NUnit. Czasami takie rozwiązanie może zaoszczędzić troszkę czasu. Zauważyłem, że bardzo często testuje metody dla takich samych danych wejściowych. Dla parametru typu string sprawdzam jak metoda zadziała dla null, pustego stringa i stringa z białym znakiem.
public class SimpleTestClass
{
    [TestCase(null)]
    [TestCase("")]
    [TestCase(" ")]
    public void SimpleTestCase(string parametr)
    {
        Assert.IsTrue(string.IsNullOrWhiteSpace(parametr));
    }
}

A gdyby tak trzymać kolekcję przypadków testowych w oddzielnym miejscu? Mamy taką możliwość - możemy użyć TestCaseSource. Niestety wszystkie metody muszą być statyczne.
[TestCaseSource(typeof(StringTestCaseSource), "NullAndWhiteSpaceStrings")]
public void It_should_return_true(string arg1)
{
   Assert.IsTrue(string.IsNullOrWhiteSpace(arg1));
}

Implementacja metody, która zwraca nam potrzebne dane testowe:
public static class StringTestCaseSource
{
public static IEnumerable<TestCaseData> NullAndWhiteSpaceStrings
{
   get
   {
     yield return new TestCaseData(null);
     yield return new TestCaseData("");
     yield return new TestCaseData(" ");
   }
}
}

Inny przypadek użycia - wartości enumów. Chcielibyśmy uruchomić test dla wszystkich przypadków enuma. Możemy podawać nazwy elementów w enumie jak i jego wartości. Dla enuma:
public enum MoneyDirection
{
        Pay,
        Receive,
}

Możemy napisać proste testy:
[TestCaseSource(typeof(EnumTestCaseSource<MoneyDirection>), "Names")]
public void It_should_parse_moneyDirection_string(string nameOfEnums)
{
           var objectEnum = Enum.Parse(typeof (MoneyDirection), nameOfEnums);
           Assert.IsNotNull(objectEnum);
}
 
[TestCaseSource(typeof(EnumTestCaseSource<MoneyDirection>), "Values")]
public void It_should_parse_moneyDirection_type(MoneyDirection valuesOfEnums)
{
           Assert.IsTrue(Enum.IsDefined(typeof(MoneyDirection), valuesOfEnums));
}
A sama implementacja metod jest następująca:
public static IEnumerable<TestCaseData> Names
{
    get
    {
                return Enum.GetNames(typeof(T))
                       .Select(x => new TestCaseData(x));
    }
}
public static IEnumerable<TestCaseData> Values
{
   get
   {
                return Enum.GetValues(typeof(T))
                      .Cast<T>()
                      .ToTestCaseData(); //with extension method
   }
}

Przypuśćmy, że mamy klasę, która zawiera statyczne formaty dat:
public class DateTimeRequiredFormats
{
        public const string Req1 = "yyyyMMdd"; //const is 
        public readonly static string Req2 = "yyyy  MM  dd";
        public static string Req3 = "yyyy MM dd";
        public string Req4 = ""; //not used because not static
        
        
        ////////////
        public string Req5 { get { return "a"; } }
        public string Req6 { get; set; }
 
        public DateTimeRequiredFormats(string req6)
        {
            Req6 = req6;
        }
 
}

Aby sprawdzić działanie statycznych formatów (Req1, Req2, Req3) wystarczyło wywołać:
[TestCaseSource(typeof(FieldTestCaseSource<DateTimeRequiredFormats>), "Static")]
public void It_should_parse_dateTimeFormat(object arg1)
{
   var dateTime = DateTime.ParseExact("20131029", arg1.ToString(), null,
               DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AllowInnerWhite );
   Assert.AreEqual(new DateTime(2013,10,29), dateTime);
}

A metoda, która zwraca te zmienne ma implementację:
public static class FieldTestCaseSource<T>
{
   public static IEnumerable<TestCaseData> Static
   {
      get
      {
         var propertyInfos = typeof(T).GetFields()
                    .Where(x=>x.IsStatic)
                    .Select(x=>x.GetValue(null))
                    ;
         return propertyInfos.ToTestCaseData();
       }
   }
 }

A co z metoda? Tutaj już jest troszkę trudniejsza sytuacja. Oprócz klasy z metodami to potrzebny będzie nam obiekt, który będzie mógł uruchomić metodę. Poniżej klasa z metodami do uruchamiania w teście:
public class InformationGetter
{
   public static int GetSuperNumber()
   {
     return 77;
   }
 
   public static int GetNotSuperNumber()
   {
      return 7;
   }
 
   public string GetCharAt(int indexNumber)
   {
      return _specialString[indexNumber]
.ToString(CultureInfo.InvariantCulture);
   }
   private string _specialString;
 
   public InformationGetter(string specialString)
   {
     _specialString = specialString;
   }
 
   public void ConsoleWrite()
   {
      Console.WriteLine("ConsoleWirte:" + _specialString);
   }
}
Poniżej sam test. Zauważ, że podany tej tutaj typ zwracany przez metodę (int).
[TestCaseSource(typeof(MethodTestCaseSource<InformationGetter,int>), "Static")]
public void It_should_return_int_bigger_than_0(MethodInvoker<int> staticMethodToInvoke)
{
   Assert.Greater(staticMethodToInvoke.Invoke(), 1);
}
public static class MethodTestCaseSource<T, TReturn>
{
   public static IEnumerable<TestCaseData> Static
   {
     get
     {
       var methodInfos=  MethodTestCaseSource<T>.GetStaticMethods()
                    .Where(x => x.ReturnType == typeof (TReturn));
       var methodInvokers = MethodInvoker<TReturn>.ToInvoker(methodInfos);
       return methodInvokers
                    .ToTestCaseData(x=>x.Method.Name);
      }
   }
   public static IEnumerable<TestCaseData> NonStatic
   {
      get
      {
        var methods = MethodTestCaseSource<T>.GetInstanceMethods()
                    .Where(x => x.ReturnType == typeof(T));
 
        var methodInvokers = MethodInvoker.ToInvoker(methods);
        return methodInvokers
                    .ToTestCaseData(x => x.Method.Name);
       }
   }
}
Klasa MethodInvoker wywołuje daną metodę. Klasa ma dwie postacie (bez i z użyciem generyków). Jedna i druga metoda ma podobną implementację.
public class MethodInvoker<TReturn> : MethodInvoker
{
   public MethodInvoker(MethodInfo methodInfo):base(methodInfo){}
 
   public TReturn Invoke(object obj=null, object[] parameters=null)
   {
     return (TReturn)Method.Invoke(obj, parameters);
   }
 
   public static IEnumerable<MethodInvoker<TReturn>> ToInvoker(IEnumerable<MethodInfo> methodInfos)
   {
     return methodInfos.Select(x => new MethodInvoker<TReturn>(x));
   }
}
Dzięki MethodInvoker możemy też przesyłać metody, które nie są statyczne. Wystarczy dla metody Invoke podać obiekt:
[TestCaseSource(typeof(MethodTestCaseSource<InformationGetter, string>), "NonStatic")]
public void It_should_return_first_char(MethodInvoker<string> nonStaticMethodToInvoke)
{
  InformationGetter getter=new InformationGetter("Abc");
  var fistCharString = nonStaticMethodToInvoke.Invoke(getter, new object[] {0});
  StringAssert.AreEqualIgnoringCase("a", fistCharString);
}

Kod źródłowy projektu jest udostępniony na GitHubie. Coś może dodam do tych kolekcji testcesów np. wygenerowane losowe stringi, dane z plików resx, najważniejsze daty w DateTime, adresy url i mail.
Możesz też zainstalować sobie paczkę nugetową. Wystarczy wpisać:
>Install-Package Nunit.Framework.TestCaseStorage



środa, 2 października 2013

Porównanie C5 z System.Collections.Generic

Jestem po lektorze książki ".NET 4.0 Generics" napisanej przez Sudipta Mukherjee (wcześniej na jego stronie można było ściągnąć całą książkę). Najbardziej cenie tą książkę za przedstawienie wyników szybkości działania różnych typów kolekcji. Autor porównuje typy, które znajdują się w bibliotece C5 oraz w System.Collections.Generic. O bibliotece C5 już wcześniej pisałem. Chciałbym przedstawić zdjęcia z wynikami z tej książki.

Eksperyment nr 1:
Ile czasu potrzeba, aby sprawdzić czy element w liście istnieje.

Eksperyment nr 2:
Ile czasu potrzeba, aby znaleźć pierwsze wystąpienie elementu w liście.


Eksperyment nr 3:
Ile czasu potrzeba, aby znaleźć ostatnio występujący element w liście


Eksperyment nr 4:
Ile czasu potrzeba, aby dodać element w losowym miejscu w liście


Eksperyment nr 5:
Ile czasu potrzeba, aby usunąć pojedynczy element w losowym miejscu w liście


Eksperyment nr 6:
Ile czasu potrzeba, aby uzyskać dostęp do elementu w kolekcji asocjacyjnej (Dictionary, SortedDictionary, C5.HashDictionary, C5.TreeDictionary)


Eksperyment nr 7:
Ile czasu potrzeba, aby znaleźć unie dwóch zbiorów


Eksperyment nr 8:
Ile czasu potrzeba, aby sprawdzić czy jeden zbiór zawiera się w drugim zbiorze


Kod źródłowy dla tych testów można było pobrać stąd. Mam nadzieję, że Sudipta reaktywuje swoją stronę.


sobota, 6 kwietnia 2013

Zapomniane C5

C5 oznacza Copenhagen Comprehensive Collecton Classes for C# i jest to biblioteka składająca się z generycznych kolekcji. C5 daje Ci większą kontrolę nad selekcja danych w kolekcjach. Programista może zdecydować czy chce mieć kolekcje zaimplementowana na funkcji haszującej (hash-based), drzewa (tree-based), tablicy (array-based) czy na LinkedList-based.


Mimo tego, że C5 ma duże zastosowanie w problemach wydajnościowych, mam wrażenie jakby biblioteka nie była popularna i projekty nieakademickie nie chcą korzystać z niej.

niedziela, 31 marca 2013

Power Collections

Power Collectons jest biblioteką powstałą w 2005 roku na platformie .NET Framework 2.0 napisanej przez firmę Wintellect. Jest to zapomniana biblioteka. Była napisana, kiedy jeszcze nie było LINQa.
Za pomocą tej biblioteki możesz wykonać iloczyn kartezjański dla kart:
var kolory = new List<string> {"Trefl", "Karo", "Kier", "Pik"};
var figury = new List<string> {"As", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Walet", "Dama", "Król"};

var karty = Algorithms.CartesianProduct(figury,kolory)
    .Select(x=>x.First + " " + x.Second)
    .ToList();

foreach (var karta in karty)
{
    Console.WriteLine(karta);
}
I jeszcze potasować te karty i zagrać w pokera :)
var kartyNaFlopie = Algorithms.RandomSubset(potasowaneKarty, 3);
foreach (  var karta in kartyNaFlopie)
{
    Console.WriteLine(karta);
}
Oprócz tego za pomoca Power Collections możesz dokonać rotacji listy.
string word = "Arkadiusz Beer ";         
for (int i = 0; i < word.Length; i++)
{
    var builder = new StringBuilder();
    Algorithms.Rotate(word.ToList(), i)
        .ToList()
        .ForEach(c=> builder.Append(c));
    Console.WriteLine(builder);
}

Power Collections posiada typy, jakich może ci brakować w BCL (m.in. MultiDictionary<TKey, TValue> czy OrderedBag<T>). Zachęcam za do sprawdzenia tej biblioteki.