Tag Archives: Testing

Working Effectively with Legacy Code – záznam, dema a slides [WUG Praha 04/2017]

Slides z mé přednášky pro WUG Praha z 26.4.2017:

Záznam z přednášky je publikován na našem HAVIT YouTube Channel.

Dotčená témata

  • „definice“ Legacy Code
  • Refactoring Mindset
  • Roslyn Code Analyzers – C#, StyleCop, SonarLint, Global Suppressions
  • Testability – extract dependencies do virtuálních metod + override v testu
  • Mocking – Moq
  • Advanced Testing – Fixture
  • extrakce dependencies, Dependency Injection

API restriction: The assembly “file:///…Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll‘ has already loaded from a different location. It cannot be loaded from a new location within the same appdomain.

Pokud se s touto chybou potkáte ve Visual Studiu, nejspíš se vám podaří něco kolem toho vygooglit. Zákeřnější je tato chyba na TFS Build Serveru, kde jsou postupy nalezené k většinou VS irelevantní.

Obvyklou příčinou je, že se vám na Build serveru spouští při testech něco víc, než plánujete.

Například

  • patternu pro assemblies s unit-testy odpovídá i jiný projekt, v mém případě např. TestHelpers.dll se sdílenými pomůckami nečekaně spadl do výchozího patternu „*test*.dll“, který na konkrétním buiĺdu nebyl změněn za námi používanou konvenci „*Tests.dll“. Můj TestHelpers.dll referencuje také Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll a chyba byla na světe.
  • pattern pro assemblies s unit-testy najde vaše testy vícekrát v různých složkách. Pomoct by mělo změnit pattern  z „**\*test*.dll“ na „*test*.dll“, aby se obešel folder-matching.

Moq: Partial mocking + cross-project internal

Není to sice ideální, ale někdy tomu situace dá, že potřebuji testovat metodu, která by jinak byla private. V takovém případě ji dělám internal a do testovacího projektu ji zpřístupňuji pomocí global atributu InternalsVisibleTo z AssemblyInfo.cs:

[assembly: InternalsVisibleTo("Havit.Xy.ServicesTests")]

To všechno funguje celkem v pohodě až do okamžiku, než se pustíte do partial-mockingu. Máme například následující třídu, kterou chceme testovat

public class TestedClass
{
  public virtual void Process()
  {
    foreach (var item in ...)
    {
      ProcessItem(item);
    }
  }

  internal virtual void ProcessItem(string item)
  {
     ...
  }
}

Dokud testujeme samotnou třídu, je vše v pohodě:

var sut = new TestedClass();
var output = sut.ProcessItem(input);

Zajímavé to začne být, pokud začneme tvořit partial-mock, tedy chceme část funkčnosti třídy nasetupovat jinak, abychom testovali jen určitou část. Třeba chceme testovat Process() bez ProcessItem():

// arrange
var sut = new Mock();
sut.Setup(sut => sut.ProcessItem(It.IsAny()).Returns(String.Empty);
sut.CallBase = true;

// act
sut.Process();

// assert
...

Najednou zjistíte, že Moq nový setup metody ProcessItem ignoruje a volá stále původní implementaci. Žádný problém navíc nehlásí a já se jen nestačím divit, co se kde hnojí.

Pak vám to najednou docvakne. Vše začne fungovat, pokud setupovanou metodu ProcessItem uděláte protected internal:

public class TestedClass
{
  public virtual void Process()
  {
    foreach (var item in ...)
    {
      ProcessItem(item);
    }
  }

  protected internal virtual void ProcessItem(string item)
  {
     ...
  }
}

…najednou vše funguje.

WatiN: Could not load file or assembly Interop.SHDocVw

Pokud by vás WatiN po instalaci z NuGetu obšťastnil hláškou ve stylu

Unhandled Exception: System.IO.FileLoadException: Could not load file or assembl y ‚Interop.SHDocVw, Version=1.1.0.0, Culture=neutral, PublicKeyToken=db7cfd3acb5 ad44e‘ or one of its dependencies. The located assembly’s manifest definition do es not match the assembly reference. (Exception from HRESULT: 0x80131040) File name: ‚Interop.SHDocVw, Version=1.1.0.0, Culture=neutral, PublicKeyToken=db

…pak je potřeba na referenci Interop.SHDocVw nastavit v Properties volbu „Embed Interop Types“ na false:

imageimage

Jinak si zkouším hrát s WatiN-em. Máte s tím někdo zkušenosti? Výhody/nevýhody proti Visual Studio Coded UI Test (mimo licenčních)?