it-swarm-eu.dev

Je staticky univerzální „zlo“ pro testování jednotek, a pokud ano, proč jej Resharper doporučuje?

Zjistil jsem, že existují pouze 3 způsoby, jak testovat jednotky (simulovat/zakázat), které jsou statické v C # .NET:

Vzhledem k tomu, že dva z nich nejsou zdarma a jeden nezasáhl vydání 1.0, zesměšňovat statické věci není příliš snadné.

Dělá to statické metody a takové „zlo“ (ve smyslu testování jednotky)? A pokud ano, proč chce resharper, abych vytvořil něco, co může být statické, statické? (Za předpokladu, že resharper není také „zlý“.)

Objasnění: Mluvím o scénáři, když chcete testovat metodu jednotkou a tato metoda volá statickou metodu v jiné jednotka/třída. Pokud ve většině definic testování jednotky necháte testovanou metodu zavolat statickou metodu v jiné jednotce/třídě, pak jste nejedná o testování jednotek, jste integrace testování. (Užitečné, ale nikoli jednotkový test.)

87
Vaccano

Když se podívám na další odpovědi, myslím, že by mohlo dojít k záměně mezi statickými metodami, které drží statický stav nebo způsobují vedlejší účinky (což mi zní jako opravdu špatný nápad), a statickými metodami, které pouze vrací hodnotu.

Statické metody, které nevykazují žádný stav a nezpůsobují žádné vedlejší účinky, by měly být snadno testovatelné jednotkou. Ve skutečnosti takové metody považuji za formu funkčního programování „chudáka“; předáte metodu objekt nebo hodnotu a vrátí objekt nebo hodnotu. Nic víc. Nevidím, jak by takové metody negativně ovlivnily testování jednotek.

108
Robert Harvey

Zdá se, že matete statický data a statický metody. Resharper, pokud si dobře pamatuji, doporučuje provést metody private v rámci statické třídy, pokud je lze provést - věřím, že to přináší malý výkon. Je ne doporučujeme, aby "cokoli, co může být" statické!

Se statickými metodami není nic špatného a lze je snadno otestovat (pokud nezmění žádná statická data). Představte si například knihovnu Maths, která je dobrým kandidátem na statickou třídu se statickými metodami. Pokud máte (vymyšlenou) metodu, jako je tato:

public static long Square(int x)
{
    return x * x;
}

pak je to mimořádně testovatelné a nemá žádné vedlejší účinky. Stačí si jen zkontrolovat, že když projdete, řekněme, 20 dostanete zpět 400. Žádný problém.

27
Dan Diplo

Pokud je zde skutečná otázka „Jak mohu testovat tento kód?“:

public class MyClass
{
   public void MethodToTest()
   {
       //... do something
       MyStaticClass.StaticMethod();
       //...more
   }
}

Poté stačí jen změnit kód a vložit jako obvykle volání do statické třídy:

public class MyClass
{
   private readonly IExecutor _externalExecutor;
   public MyClass(_IExecutor executor)
   {
       _exeternalExecutor = executor;
   }

   public void MethodToTest()
   {
       //... do something
       _exetrnalExecutor.DoWork();
       //...more
   }
}

public class MyStaticClassExecutor : IExecutor
{
    public void DoWork()
    {
        MyStaticClass.StaticMethod();
    }
}
18
Sunny

Statika nemusí být nutně zlá, ale může omezit vaše možnosti, pokud jde o testování jednotek pomocí falzifikátů/falešných/útržků.

Existují dva obecné přístupy k zesměšňování.

První (tradiční - implementovaný RhinoMocks, Moq, NMock2; ruční falešné a pahýly jsou také v tomto táboře) se spoléhá na zkušební švy a injekce závislosti. Předpokládejme, že testujete jednotku nějaký statický kód a má závislosti. V kódu navrženém tímto způsobem se často stává, že statika vytváří své vlastní závislosti a invertuje inverzi závislosti . Brzy zjistíte, že nemůžete aplikovat zesměšněná rozhraní do testovaného kódu, který je navržen tímto způsobem.

Druhý (simulovat cokoli - implementovaný TypeMock, JustMock a Moles) se spoléhá na .NET's Profiling API . Může zachytit všechny vaše instrukce CIL a nahradit část kódu kódem falešný. To umožňuje TypeMock a dalším produktům v tomto táboře zesměšňovat cokoli: statiku, uzavřené třídy, soukromé metody - věci, které nejsou navrženy tak, aby byly testovatelné.

Probíhá debata mezi dvěma myšlenkovými školami. Jeden říká, dodržujte principy SOLID a vytvořte testovatelnost (která často zahrnuje jít snadno na statiku). Druhý říká, že kupte TypeMock a nebojte se.

15
azheglov

Podívejte se na toto: "Statické metody jsou smrt testovatelností" . Stručné shrnutí argumentu:

Chcete-li testovat jednotku, musíte vzít malý kus kódu, znovu zapojit jeho závislosti a otestovat jej izolovaně. To je obtížné u statických metod, a to nejen v případě, že přistupují ke globálnímu stavu, ale i když pouze volají jiné statické metody.

14
Rafał Dowgird

Jednoduchá pravda se málokdy připouští, že pokud třída obsahuje závislost viditelnou na kompilátoru na jiné třídě, nelze být testována izolovaně od této třídy. Můžete předstírat něco, co vypadá jako test, a objeví se ve zprávě, jako by to byl test.

Ale nebude mít klíčové vlastnosti testu; selhání, když jsou věci špatné, projíždění, když mají pravdu.

To platí pro všechna statická volání, volání konstruktorů a jakýkoli odkaz na metody nebo pole, která nebyla zděděna ze základní třídy nebo rozhraní . Pokud se v kódu objeví název třídy, jedná se o závislost viditelnou kompilátorem a bez ní nelze platně otestovat. Jakýkoli menší kus je jednoduše nikoli platná testovatelná jednotka. Jakýkoli pokus zacházet s ním, jako by to bylo, nebude mít výsledky nic smysluplnějšího, než napsat malou utilitu k vydání XML používaného vaším testovacím rámcem pro vyslovení 'test vyhověl'.

Vzhledem k tomu existují tři možnosti:

  1. definovat testování jednotky pro testování jednotky složené ze třídy a její pevně zakódované závislosti. Funguje to tak, že se vyhnete kruhovým závislostem.

  2. nikdy nevytvářejte závislosti kompilace mezi třídami, které jste zodpovědní za testování. Funguje to, pokud vám nevadí výsledný styl kódu.

  3. netestujte jednotku, místo toho test integrace. Která funguje, pokud není v rozporu s něčím jiným, co potřebujete použít pro testování termínu integrace.

5
soru

Neexistují dva způsoby. Návrhy ReSharperu a několik užitečných funkcí C # by se nepoužívaly tak často, pokud byste psali izolované testy atomových jednotek pro celý váš kód.

Například, pokud máte statickou metodu a musíte ji odstranit, nemůžete použít, dokud nepoužijete izolační rámec založený na profilu. Řešení kompatibilní s volání je změnit horní část metody použití notace lambda. Například:

PŘED:

    public static DBConnection ConnectToDB( string dbName, string connectionInfo ) {
    }

PO:

    public static Func<string, string, DBConnection> ConnectToDB (dbName, connectionInfo ) {
    };

Oba jsou kompatibilní s hovory. Volající se nemusí měnit. Tělo funkce zůstává stejné.

Poté ve svém kódu Unit-Test můžete toto volání vložit jako takové (za předpokladu, že se jedná o třídu nazvanou Databáze):

        Database.ConnectToDB = (dbName, connectionInfo) => { return null|whatever; }

Po dokončení jej opatrně nahraďte původní hodnotou. Můžete to provést pomocí zkuste/konečně, nebo v rámci testu jednotky, který se volá po každém testu, napište kód, jako je tento:

    [TestCleanup]
    public void Cleanup()
    {
        typeof(Database).TypeInitializer.Invoke(null, null);
    }

který znovu vyvolá statický inicializátor vaší třídy.

Funkce Lambda Funcs nejsou tak bohaté na podporu jako běžné statické metody, takže tento přístup má následující nežádoucí vedlejší účinky:

  1. Pokud byla statická metoda rozšířením, musíte ji nejprve změnit na metodu bez rozšíření. Sběratel to může udělat za vás automaticky.
  2. Pokud je některý z datových typů statických metod sestavou s vloženým interopem, například pro sadu Office, musíte metodu zalomit, zalomit typ nebo ji změnit na typ „objekt“.
  3. Už nemůžete používat nástroj pro změnu podpisu Resharperu.

Řekněme však, že se úplně vyhnete statice a převedete ji na instanční metodu. Stále to nelze zesměšňovat, pokud není metoda virtuální nebo implementovaná jako součást rozhraní.

Takže ve skutečnosti každý, kdo navrhuje nápravu statických metod, je učinit z nich instanční metody, byly by také proti instančním metodám, které nejsou virtuální nebo součástí rozhraní.

Proč tedy má C # statické metody? Proč to umožňuje metody nevirtuální instance?

Pokud používáte některou z těchto „funkcí“, pak jednoduše nemůžete vytvořit izolované metody.

Kdy je tedy používáte?

Použijte je pro jakýkoli kód, který neočekáváte, že by někdo někdy chtěl vynechat. Několik příkladů: metoda Format () třídy String, metoda WriteLine () třídy Console, metoda Cosh () třídy Math

A ještě jedna věc .. Většina lidí se o to nestará, ale pokud můžete o provedení nepřímého hovoru, je to další důvod, proč se vyhnout metodám instance. Jsou případy, kdy jde o výkonnostní zásah. To je důvod, proč neexistují virtuální metody.

4
zumalifeguard

Vidím, že po dlouhé době nikdo zatím neuvedl opravdu jednoduchý fakt. Pokud mi resharper řekne, že můžu udělat metodu statickou, znamená to pro mě obrovskou věc, slyším jeho hlas, jak mi říká: „Hej, tyhle logiky nejsou odpovědností aktuální třídy, abych to zvládl, takže by měla zůstat venku v nějaké pomocné třídě nebo tak něco ".

3
g1ga
  1. Věřím, že je to částečně proto, že statické metody jsou "rychlejší" než metody instance. (V uvozovkách, protože to voní mikro optimalizací) viz http://dotnetperls.com/static-method
  2. Říká vám, že to nepotřebuje stav, a proto by ho bylo možné zavolat odkudkoli, čímž by se režijní náklady na instataci odstranily, pokud je to jediné, co někdo potřebuje.
  3. Pokud to chci zesměšňovat, pak si myslím, že je to obvykle praxe, která je deklarována na rozhraní.
  4. Pokud je deklarováno na rozhraní, pak R # nenavrhne, aby byl statický.
  5. Pokud je deklarován jako virtuální, pak R # nenavrhne, aby byl také statický.
  6. Statický stav (pole) je něco, co by mělo být vždy pečlivě zváženo . Statický stav a vlákna se mísí jako lithium a voda.

R # není jediný nástroj, který tento návrh vytvoří. FxCop/MS Code Analysis bude také dělat to samé.

Obecně bych řekl, že pokud je metoda statická, měla by být obecně testovatelná stejně. To přináší určité úvahy o designu a pravděpodobně více diskuse, než mám teď v prstech, takže trpělivě čeká na hlasování a komentáře ...;)

3
MIA

Pokud se vyvolá statická metoda z vnitř jiné metody, není možné takovému hovoru zabránit nebo ho nahradit. To znamená, že tyto dvě metody vytvářejí jednu jednotku; Jednotkový test jakéhokoli druhu je testuje oba.

A pokud tato statická metoda hovoří k Internetu, připojuje databáze, zobrazuje vyskakovací okna GUI nebo jinak převádí test jednotky na úplný nepořádek, jednoduše to bez jakékoli snadné práce obejde. Metoda, která volá takovou statickou metodu, nelze otestovat bez refaktoringu, i když má spoustu čistě výpočetního kódu, který by byl z testování jednotky velmi přínosný.

2
h22

Věřím, že vám Resharper dává vodítko a aplikuje pokyny pro kódování, se kterými byl nastaven. Když jsem použil Resharper a řekl mi, že metoda by měla být statická, je vázána na soukromou metodu, která nepůsobí na žádné proměnné instance.

Nyní, pokud jde o testovatelnost, tento scénář by neměl být problém, stejně byste neměli testovat soukromé metody.

Pokud jde o testovatelnost statických metod, které jsou veřejné, pak je testování jednotek obtížné, když se statické metody dotknou statického stavu. Osobně bych to udržoval na minimu a používal statické metody co nejčistěji jako funkce, kde jsou případné závislosti předávány metodě, kterou lze ovládat pomocí zkušebního přípravku. Jedná se však o rozhodnutí o návrhu.

0
aqwert