1

I have a class that looks like this:

public int DoWork(int value) 
{
    return value + GetDataFromDB();
}

public int GetDataFromDB()
{
    return 10;
}

In the real world the second function goes out to the database and gets the value, which is not what I want for unit tests.

Using FakeItEasy my test looks something like this:

public void DoWorkTest()
{
    // Arrange
    DoWorkClass fake = new DoWorkClass(config);
    A.CallTo(() => fake.GetDataFromDB()).Returns(1);

    // Act
    int result = fake.DoWork(5);

    // Assert
    Assert.That(result, Is.EqualTo(6));
}

However this throws an error:

System.ArgumentException : Object 'DoWorkClass' of type DoWorkClass is not recognized as a fake object

How do I use FakeItEasy to fake the database call function?

2
  • 2
    The answers show you how to do it, but the problem here is that your DoWorkClass should be accepting the data access component in its constructor, which your unit test can mock. The "config" you're passing suggests database configuration, which means the class is responsible for too much , both data access and business logic. What ends up happening is 1) your tests become tautological (it passes because the test was written in a way that it will always pass), and/or 2) your tests have to deal with implementation details (not appropriate for unit tests). Commented Sep 30 at 19:30
  • Your "fake" is not a fake, it's just an instance of your class. And anyway, it looks like DoWorkClass is what you want to test, so there's no point in faking it; you want to test the real thing. What you need to do is extract the external dependencies (e.g. DB access) to separate classes, and fake that. Commented Oct 1 at 11:55

2 Answers 2

2

First of all you need to create fake properly with A.Fake

var fake = A.Fake<DoWorkClass>();

Then, you would have error, that you cannot mock the method, so you have to make it virtual:

public virtual int GetDataFromDB()

As a side note, you cannot mock concrete implementation. That is why it is recommended to use interfaces (so you should define IDoWorkClass interface). Other options are to:

  • define class as abstract
  • define method as abstract

Also you should split dependency to database into separate service and "hide" it behind the interface. This way you could make it even more testable.

Sign up to request clarification or add additional context in comments.

1 Comment

While that would work, I would definitely not recommend that approach. External dependencies should absolutely be in separate classes, and injected into the class being tested.
2

FakeItEasy can only fake interfaces or virtual/abstract methods on classes. In your example, GetDataFromDB() is a non-virtual method, so FakeItEasy cannot intercept or override it.

**Your first option is to use an interface like below: **

public interface IDataProvider
{
    int GetDataFromDB();
}

public class DoWorkClass
{
    private readonly IDataProvider _dataProvider;

    public DoWorkClass(IDataProvider dataProvider)
    {
        _dataProvider = dataProvider;
    }

    public int DoWork(int value)
    {
        return value + _dataProvider.GetDataFromDB();
    }
}

Then your test for that will become as follows:

[Test]
public void DoWorkTest()
{
    // Arrange
    var fakeDataProvider = A.Fake<IDataProvider>();
    A.CallTo(() => fakeDataProvider.GetDataFromDB()).Returns(1);

    var doWork = new DoWorkClass(fakeDataProvider);

    // Act
    int result = doWork.DoWork(5);

    // Assert
    Assert.That(result, Is.EqualTo(6));
}

The second option is: If you can't use interfaces, you can make the method virtual and then fake the class:

public class DoWorkClass
{
    public virtual int GetDataFromDB()
    {
        return 10;
    }

    public int DoWork(int value)
    {
        return value + GetDataFromDB();
    }
}

then your test will look like this:

[Test]
public void DoWorkTest()
{
    var fake = A.Fake<DoWorkClass>();
    A.CallTo(() => fake.GetDataFromDB()).Returns(1);
    A.CallTo(() => fake.DoWork(5)).CallsBaseMethod();

    int result = fake.DoWork(5);

    Assert.That(result, Is.EqualTo(6));
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.