I have the following Interface & Class and I also wrote a unit test as shown down, but I got an exception:
Assertion failed for the following call: AsyncConsole.example1.IPlayer.Start(i: 1) Expected to find it once or more but didn't find it among the calls:
Is there a way to solve that?
public interface IPlayer
{
public void Play();
public void Start(int i);
}
public class Player : IPlayer
{
public void Play()
{
Start(1);
}
public void Start(int i)
{
Console.WriteLine("Start " i);
}
}
Test class
using FakeItEasy;
using Xunit;
namespace TestProject
{
public class TestPlayer
{
[Fact]
public void Play_WhenCalled_ShouldCallStart()
{
var player = A.Fake<IPlayer>();
player.Play();
//assert
A.CallTo(() => player.Start(1)).MustHaveHappened();
}
}
}
Message:
FakeItEasy.ExpectationException :
Assertion failed for the following call:
AsyncConsole.example1.IPlayer.Start(i: 1)
Expected to find it once or more but didn't find it among the calls:
1: IPlayer.Play()
CodePudding user response:
You can't check the calls of the Start
method because you expect to IPlayer.Start() call but what actually happened is when you call the Play
method of the IPlayer
interface, behind the scenes Player.Start(1) calls. In other words interface just a black box and you don't what happened inside. actually, the whole point of Unit testing is that. you have black-box and the only thing you can test are expectations of outputs.
CodePudding user response:
As @Milad Karimifard says, it's unusual to write a test that checks to see if a class calls one of its other methods. Typically you'd be testing the return values of a method, or perhaps that a method called another method on a collaborating object.
One way to do that would be to inject a "console-like" interface into your Player
class, and in your test supply a fake one. You could then see if IConsole.WriteLine
were called with the expected value.
However, if you're set on continuing to check to see if Player
calls its own methods, you need to make a number of adjustments:
- Fake
Player
, notIPlayer
. There's no implementation in an interface, so a fakeIPlayer
will never execute any of thePlayer
code. - Make
Player.Start(int)
virtual. Otherwise, there's no way for FakeItEasy to intercept the calls and change behaviour.
You'll likely end up with something like this (IPlayer
need not change):
public class Player : IPlayer
{
public void Play()
{
Start(1);
}
public virtual void Start(int i)
{
Console.WriteLine("Start " i);
}
}
[Fact]
public void Play_WhenCalled_ShouldCallStart()
{
var player = A.Fake<Player>();
player.Play();
//assert
A.CallTo(() => player.Start(1)).MustHaveHappened();
}