Mockowanie klasy

0

Witam. Mam problem z mockowaniem jednej z klas. Jest to bardzo podstawowy poziom, i nie wiem czy dokladnie rozumiem idee mockowania, ale od poczatku.

Mamy klase Byte4, ktora to wlasnie testuje. W jednej z metod, uzywam innej klasy, Frame, ktora posiada metode ktora wykonuje skomplikowane operacje i zwraca bool. Jest to klasa ktora chcialbym zamockowac.

W moich testach chce wytestowac ta metode, ktora wlasnie wykorzystuje ta skomplikowana metode.

Mozecie dac jakas podpowiedz co robie zle?

metoda testujaca:

 
[TestMethod]
public void IsGoodTest()
{
    m_byte = new Byte4_Accessor(5);
    var mockTest = new Mock<Frame>();
    mockTest.Setup(par => par.Verify((Byte4) m_byte.Target)).Returns(true);
}

metoda ktora testuje:

public int IsGood()
{
    Frame frame = new Frame();
    if (frame.Verify(this))
    {
        if ((m_byte % 2) == 0)
            return 1;
        return 0;
    }
    return -1;
}

powiedzmy ze metoda ktora chce zamockowac:

public virtual bool Verify(Byte4 a_byte)
{
    System.Threading.Thread.Sleep(10000);
    return true;
}

Mialem nadzieje ze ten kod zadziala tak, ze moja klasa jednak wykorzysta zmockowana metode... ale jednak nie, wiec mozecie podpowiedziec jak to rozwiazac?

0

Tak nie zadziala. Mocki zwykle (a na pewno w przypadku Moq) dzialaja tak, ze tworzona jest klasa dziedziczaca i nadpisywane jest dzialanie metody, ktora chcemy podmienic. Stad np. wymaganie, zeby metody byly wirtualne i stad mockowanie interfejsow nigdy nie jest problemem (mock jest implementacja interfejsu). W Twoim wypadku nie dziala to z tego powodu, ze tworzysz instancje mocka (klasa pochodna Frame), ustawiasz oczekiwane wartosci i ... nic. W metodzie testowanej tworzysz nowa instancje (tym razem klasy Frame), ktora wykorzystujesz do przeprowadzenia dzialan. Moq w zaden magiczny sposob nie domysli sie, ze ta akurat instancja ma dzialac jak inna instancja (testowa), ktora ustawiles wczesniej.
Musisz jakos przekazac testowa instancje, zeby za jej pomoca zostaly przeprowadzone dzialania.
Np.:

class MyClass:
{
	private Frame frame;
	 
	public MyClass(Frame frame)
	{
	this.frame = frame;
	}
	public int IsGood()
	{
		if (frame.Verify(this)) //tutaj wykorzystany bedzie jakikolwiek obiekt przekazany w konstruktorze, np. mock
		{
			if ((m_byte % 2) == 0)
				return 1;
			return 0;
		}
		return -1;
	}
}
[TestMethod]
public void IsGoodTest()
{
    m_byte = new Byte4_Accessor(5);
    var mockTest = new Mock<Frame>();
    mockTest.Setup(par => par.Verify((Byte4) m_byte.Target)).Returns(true);
    var myclass = new MyClass(mockTest.Object);//tutaj oszukujemy klase testowana twierdzac, ze podajemy dobry obiekt.
    Assert.Something(myclass.IsGood());
}

Jeszcze ladniej byloby stworzyc interfejs, ktory zaimplementuje klasa Frame i mockowac interfejs. Wtedy nie ma potrzeby ustawiac wirtualnosci metody, a poza jest to lepiej zaprojektowany kawalek kodu, zgodnie z podejscie Inversion of Control.

class MyClass:
{
	private IFrame frame;

	public MyClass(IFrame frame) //tutaj okreslamy, ze nasza klasa wymaga do dzialania konkretnego obiektu, ktory implementuje dany interfejs - czyli spelnia dany kontrakt. Niewazne co to jest, wazne, ze ma metody, ktore nas interesuja - nie powinnismy wnikac czy to jest taka czy inna klasa, dopoki obiecuje (interfejs), ze robi to czego wymagamy.
	{
	this.frame = frame;
	}
}

0 użytkowników online, w tym zalogowanych: 0, gości: 0