Klávesové zkratky na tomto webu - rozšířené Na obsah stránky

Using pattern

15.32 - 14. dubna 2008 | ASP.NET 2.0

Je tomu již dlouhá doba, co jsem psal spotík o užívání bloku using v jazyce C# pro třídy implementující rozhranní System.IDisposable. Tohoto bloku se dá využít k logickému členění kódu do bloků a vytvořit tak syntax sugar na úrovni API.

Ukázky užití

S using patternem se v moderních API dá potkat celkem často. První ukázka je z mockovacího frameworku Rhino Mocks. Používá se pro nahrávání a přehrávání chování mockovaného objektu.

MockRepository mocks = new MockRepository();
IDependency dependency = mocks.CreateMock<IDependency>();

using(mocks.Record()) {
    Expect.Call(dependency.GetSomething("parameter")).Return("result");
    dependency.DoSomething();
}

using(mocks.Playback()) {
    Subject subject = new Subject(dependency);
    subject.DoWork();
}

Using pattern usnadňuje čtení takovéhoto kódu a hned je jasná i logická struktura.

Další ukázka pochází z ASP.NET MVC frameworku, kde se using pattern používá v HTML helperu pro generování formuláře.

<% using(Html.Form<HomeController>(action => action.Index())) { %>
...
<% } %>

Implementace

Základem, tedy, je blok using, který slouží k bezpečnému zavolání metody Dispose objektu implementujícího rozhranní System.IDisposable. Jak na to, když v using bloku předáváme metodu a ne objekt? Jednoduše, musíme vrátit v metodě objekt, který se o špinavou práci postará. V podstatě ani nemusí být nijak inteligentní.

public class UsingPattern : IDisposable {

  private WorkerMethod _method;

  public delegate void WorkerMethod();

  public UsingPattern(WorkerMethod method) {
    _method = method;
  }

  public void Dispose() {
    _method();
  }
}

Užití v našem API je pak celkem triviální.

public class SomeClass {
  public UsingPattern SomeMethod() {
    Console.WriteLine("Zacatek bloku");
    return new UsingPattern(() => Console.WriteLine("Konec bloku"));
  }
}

public class OtherClass {
  public void Consumer() {
    var some = new SomeClass();

    using (some.SomeMethod()) {
      Console.WriteLine("Blok");
    }
  }
}

Tagy: ,

Redakční systém na ASP.NET MVC

18.56 - 23. prosince 2007 | Webdesign

Rozhodl jsem se, že, jako praktickou ukázku použití TDD a ASP.NET MVC (dále jen MVC), budu psát seriálek, výsledkem něhož bude základ třetí verze redakčního systému Gryphoon.

Upozornění: Je možné, že některým věcem nebudete v průběhu čtení rozumět. Dopuručuji si přečíst související články, na jejichž základě tento seriál staví.

Už z této podstaty vyplívá, že půjde o OSS. Projekt je hostován na Codeplexu pod MS-PL. Dalším důležitým znakem je použití Texy.net jako základního kamene systému, spojení s databází bude zajišťovat Castle ActiveRecord, pro testování použiji xUnit.net a Rhino Mocks. Tím jsou nastíněny základní prvky architektury a můžeme se pomalu dát do práce.

Struktura projektu

Prozatím to vypadá na tři projekty v řešení:

  1. Rarous.Gryphoon – Knihovna, jádro systému, které bude obsahovat objekty doménového modelu, konfiguraci a další potřebné komponenty.
  2. Rarous.Grypho­on.Spec – Knihovna s jednotkovými testy. xUnit.net místo termínu test používá fakt, proto bude brát tento projekt jako specifikaci zbylých částí.
  3. Rarous.Grypho­on.Web – Webová aplikace. Projekt bude obsahovat webovou část tj. Controllery a View (řadiče a pohledy) a Helpery (pomocníky).

První řádky specifikace

Naší jedinou specifikací bude projekt Rarous.Grypho­on.Spec. Tím co je v něm dáno, by se měly řídit oba zbylé projekty. Dobrým zvykem v TDD je navrhovat systém od shora dolů. První věc, se kterou přijdete do styku, je URL. Zatím nebudu výchozí schéma URL měnit, proto ani nebudu psát testy na Routování (zatím). Defaultní schéma URL by mělo být už milionkrát otestované v rámci MVC projektu.

Takže budeme pokračovat dál a to k řadiči článku (ArticleController). Ten by měl být zodpovědný za vytváření článků nových, jejich následnou editaci, zobrazování a v poslední řadě i mazání.

V prvním CTP, zatím nejsou předdefinované Mock Objekty pro controllery, proto použijeme Test subclass pattern, pro ověření činnosti controlleru. Controller bude mít následující rozhranní:

Diagram IArticleController

A třída pro testování vypadá následovně:

public class TestArticleController : ArticleController {
  public string ActualViewName { get; set; }
  public string RedirectViewName { get; set; }
  public string ActualMasterName { get; set; }
  public object ActualViewData { get; set; }

  protected override void RenderView(string viewName, string masterName,
                                     object viewData) {
    ActualViewName = viewName;
    ActualMasterName = masterName;
    ActualViewData = viewData;
  }

  protected override void RedirectToAction(object values) {
    RedirectViewName = values.ToDictionary()["Action"];
  }
}

Teď můžeme napsat první test, který ověří, že pokud přijdeme na adresu /article/ otevře se nám editor nového článku. Pozn. Využívám výchozího schématu routeru [controller]/[action]/[id] -Pokud není action definovaná vybere se Index. V budoucnu ho změním na lepší, ale pro začátek stačí.

[Fact]
public void ArticleController_DefaultActionShouldShowEditor() {
  TestArticleController controller = new TestArticleController();

  controller.Index();

  Assert.Equal("Editor", controller.ActualViewName);
}

Spustíme test – neprojde. Aby test prošel, musíme doimplementovat metodu ArticleController.Index.

[ControllerAction]
public void Index() {
  RenderView("Editor");
}

Teď už by měl test projít. Jenže aby to fungovalo i na webu, musíme ještě dopsat View /Views/Article/Editor.aspx… Do příště za domácí úkol.

Závěrem

Aktuální stav je na codeplexu ke stažení, ale zdaleka není funkční. :) Průběžně ho budu s dalšími díly doplňovat. Příště tedy uděláme ukládání nových příspěvků a editaci. Když se pozorně podíváte na zdrojáky, zjistíte, že tak trochu cheatuju :)

Jo abych nezapoměl, pokud jste sem přišli přes RSS a ještě jste si nezměnili adresu feedu, učiňte tak zavčasu. Děkuji

Související

Tagy: ,

Nový Unit Test Framework pro dotnet

19.35 - 7. října 2007 | ASP.NET 2.0

Přibližně před dvěma týdny byla vypuštěna první beta verze nového testovacího frameworku xUnit.net. Spousta lidí si říká, k čemu další framework – vždyť tu máme NUnit, MbUnit, MsTest – a navíc syntakticky nekompatibilní?

xUnit.net přináší eleganci, jednoduchost a zdravý rozum. Byly zrušeny SetUpy a TearDowny a nahrazuje je IDisposable pattern a konstruktor (jednoduše elegantní), pro každý test je vždy vytvořena nová instance testovací třídy. Asserty byly revidovány a duplicitní či zbytečné byly odebrány.

Framework je navržen tak, aby byl snadno rozšiřitelný o vlastní atributy, kterými můžete specifikovat vlastní akce (např. Authetifikaci) či požadavky. Součástí frameworku není žádný mockvací nástroj. K čemu také, když už tu máme skvělé Rhino Mocks?

Nové možnosti

Běžnou praxí je na testy zakládat samostatný projekt, takže jsou testy v samostatné assembly. Pokud jste chtěli mít testy společně v jednom projektu s výkonným kódem mohli jste tak taktéž učinit. Jenže pořád je tu problém, pokud z nějakého důvodu potřebujete testovat privátní věci. Sice to je ukázka toho, že něco smrdí, ale stejně se to občas může hodit.

xUnit.net totiž ruší atribut TestFixture/TestClass a při spouštění test prohledává všechny třídy na přítomnost metod s atributem Test. To nám umožňuje mít testovací metody v jedné třídě společně s výkonným kódem a testovat tak privátní členy bez nutnosti používat reflexi. Když už se k něčemu takovému rozhodnete je dobré ještě využít partial class a testy přesunout do samostatného souboru např. Class.tests.cs

Soubor SomeClass.cs:

public partial class SomeClass {
  private bool _isDirty;
  private string _someText;

  public string SomeText {
    set {
      _isDirty = true;
      _someText = value;
    }
  }
}

Soubor SomeClass.tests.cs

public partial class SomeClass {
  [Test]
  private void SettingSomeTextMakesSomeClassDirty() {
    var testInstance = new SomeCLass();
    Assert.False(testInstance._isDirty);
    testInstance.SomeTest = "text";
    Assert.True(testInstance._isDirty);
  }
}

Také je celkem dobré nechat takové testovací metody skryté před vnějším světem, tak že jim nastavíme modifikátor viditelnosti na private. xUnit.net umí spouštět i privátní a interní metody za účelem testování (platí pro beta2 a novější).

Osobně se mi tento framework velice líbí a už jsem na něj přepsal testy pro Texy.net.