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.

Zanechat odpověď

Vyplňte detaily níže nebo klikněte na ikonu pro přihlášení:

Logo WordPress.com

Komentujete pomocí vašeho WordPress.com účtu. Odhlásit /  Změnit )

Facebook photo

Komentujete pomocí vašeho Facebook účtu. Odhlásit /  Změnit )

Připojování k %s