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



niedziela, 20 października 2013

Fluent notation

Osoby, które kodują razem ze mną to od razu wiedzą, że jestem autorem danej części kodu. Pisany kod jest w stylu Fluent notation ( również zwany Fluent interface, gdyż przygotowujesz całe API). Co prawda wielu osobom się to nie podoba, ale chciałbym Ci przedstawić mój sposób widzenia:

Zapis LINQ w tradycyjny jednolinijkowy sposób pisania kod:
var firstNumberSelector = GetNumbers().Where(x => x > 0).
    ToLookup(x => x.ToString().First()).Select(x => new{x.Key, Items = x,Count = x.Distinct().Count()}).ToList();

A tutaj mój sposób pisania kodu:
var firstNumberSelector = GetNumbers()
                .Where(x => x > 0)
                .ToLookup(x => x.ToString()
                                .First())
                .Select(x=>new {x.Key, 
                                Items=x, 
                                Count=x.Distinct()
                                        .Count()})
                .ToList();
Projekt Fluent NHibernate korzysta z takiego zapisu i kod może wyglądać tak:
_SessionFactory = Fluently 
                .Configure() 
                .Database(MsSqlCeConfiguration 
                              .Standard 
                              .ConnectionString("Data Source=MyDb.sdf") 
                              .ShowSql()
                               )
                .Mappings(m => m.FluentMappings 
                           .AddFromAssemblyOf<NHibernateHelper>()) 
                .ExposeConfiguration(cfg => new SchemaExport(cfg) 
                                        .Create(true, true)   //create table in db 
                                        ) 
                .Cache(c=>c 
                    .UseSecondLevelCache() 
                    .UseQueryCache() 
                    .ProviderClass<HashtableCacheProvider>() 
                    ) 
                .BuildSessionFactory();
Dla mnie jest to kod bardziej czytelny i łatwiej mi jest określić jaka metoda jest uruchamiana dla danego obiektu.
Może Tobie też spodoba się taki sposób pisania kodu.

środa, 16 października 2013

Kolorowanie składni w Visual Studio

Edytor środowiska programistycznego (IDE) jest narzędziem, przy którym programista spędza 99% swojego czasu. Nie będę Ci mówił, że kolorowa składnia jest bardzo ważna. Celem tego wpisu jest przesłanie Ci ciekawych rozwiązań zestawu kolorów.

Już dawno temu Atwood, Hanselman czy Restrepo pisali o kolorowaniu środowiska programistycznego.

Na stronie Studio Style można pobrać style do edytora Visual Studio. Oprócz tego sam możesz stworzyć własny styl dopasowany do Twojego gustu. Oczywiście w każdym momencie można wrócić do domyślnego stylu.

Dla Visual Studio 2013 (i innych wersji od VS2010) jest jeszcze dodatek Color Theme Editor, który zmieniasz menu VS.

niedziela, 13 października 2013

Jestem OK ponieważ

Czy Ty jesteś OK
Zrób takie małe ćwiczenia. Zapisz 4 zdania określające Ciebie, czy jesteś w porządku. Np.
Jestem OK, dopóki pomagam innym
Jestem OK, bo mam luksusowy dom
Jestem OK, ponieważ noszę markowe ubranie
Jestem OK, gdyż jestem poważany

Teraz napisz 4 zdania określające ciebie.
Napisz teraz.





Z pewnej książki zapoznałem się z metodyką "Jestem Ok, ponieważ ..."
Jest to metoda, która uświadomiła mnie jakie mam lęki, dlaczego moje wartości są kruchliwe oraz wzmocniła moje poczucie własnej wartości.

Jest to metoda, która określa Twój szacunek do samego siebie. Na przykład, jeśli rodzice chwalili cię wtedy kiedy zdobywałeś dobre oceny w szkole to mówiłeś do siebie "jestem OK, dopóki mam dobre oceny". Z biegiem lat mogłeś rozwinąć warunkowe poczucie własnej wartości i jeżeli nic nowego się nie zdarzyło, to taka "wartość" towarzyszyła Ci przez okres dojrzałości prowadzać do rozczarowań oraz wątpliwości we własne możliwości, kiedy nie będzie odnosiło się sukcesów.
Warunkowa wartość jest rozwijana wewnątrz nas. Problem powstaje, kiedy takiego warunku nie jesteśmy w stanie spełnić, co będzie prowadziło do poczucia niskiej wartości. Zamiast takiej wartości można zadać sobie wartość Jestem OK, niezależnie od tego czy odnoszę sukces.

Inne warunki określające naszą wartość to:
Jestem OK, ponieważ uczę się
Jestem OK, ponieważ wygrywam
Jestem OK, ponieważ jestem wolontariuszem
Jestem OK, ponieważ ciężko pracuję
Jestem OK, ponieważ znam się na kinie
Jestem Ok, bo dużo zarabiam
Jestem OK, dopóki mam co robić
Jestem OK, dopóki mam wiele przyjaciółek
Jestem OK, dopóki jestem dla kogoś ważny/-na
Jestem OK, dopóki pomagam innym
Jestem OK, bo jadam w drogich restauracjach
Jestem OK, bo jestem z moim partnerem/-ką
Jestem OK, bo jestem uczciwy
Jestem OK, bo kontroluje innych
Jestem OK, bo chodzę w modnym ubraniu
Jestem OK, bo chodzę na siłownię
Jestem OK, bo wiem co jest smaczne
Jestem OK, bo znam się na nowościach technologicznych




Przez warunkową wartość możemy robić coś, co nie daje nam satysfakcji. Dążenie do celu nie jest z powodu chęci (motywacja pozytywna), ale z powodu strachu (motywacja negatywna). Dochodzi do tego, że można wykonać cele wbrew naszym wewnętrznym wartościom. Sprawdź czy Twoje cele są zgodne z Twoimi wartościami.

piątek, 11 października 2013

Microsoft Security Fundamentals

Ostatnio zdałem egzamin MTA:Security Fundamentals 98-367

Z dwóch powodów polecam ten egzamin osobom pracującym w firmach, które dbają o bezpieczeństwo (instytucje finansowe, banki, ubezpieczenia, firmy medyczne itp.)

1) przygotowanie się do tego egzaminu pozwali Ci na zaznajomienie się z podstawowymi technikami włamywania się do firm, a w szczególności uświadamia ludzi o socjotechnikach
2) egzamin jest nakierowany na teoretyczną i ogólną wiedzę, a nie na szczegóły implementacji. Osoby, które twierdzą, że Microsoft jest 'beee' i nie znają jego produktów mogą zdać ten egzamin. Co prawda pamiętam jedno pytanie z BitLockera (microsoftowy TruCrypt) i o wersje Windows, w której to rozwiązanie jest używane (źle odpowiedziałem), ale było to jedno pytanie.

Jeżeli byś chciał się przygotować do niego to przydatny będzie Ci oficjalny przewodnik po tym egzaminie
Dodatkowo możesz poczytać inne książki z obszaru bezpieczeństwa Windows - na przykład Google books udostępniło książkę Windows Security Essencials.

Obejrzałem jeszcze filmiki na trainsignal.com oraz cbt nuggets.

Wydaje mi się, że książka przygotowująca do egzaminu w zupełności by wystarczała, ale wiedzy nigdy za wiele.

sobota, 5 października 2013

Walka z CSS

Tak się zastanawiam i dochodzę do wniosku, że osoby, które potrafią stworzyć piękne strony za pomocą modyfikacji css'a muszą mieć coś z artysty. Ja (niestety) nie mam takiej umiejętności, a bardzo bym chciał. Może w przyszłości troszkę się pobawię, ale zawsze jak biorę się za selectory, to muszę całą stronę zepsuć.
Rozbawiła mnie znaleziona grafika Petera Griffina jak próbuje ustawić żaluzje i fantastycznie przedstawia moją walkę z CSS.

ś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ę.