1

I am using .CallBase() in order to execute the real code behind the mock for the .Export() method from within the TsExporter class.

On the other side, the .RetrieveTranslations() is executing the real code too, and not returning the mocked value as "I told it to do it".

Here is the code:

[TestFixture]
public class TestClass
{
    private Mock<ITsExporter> _tsExporter;

    [SetUp]
    public void SetUp()
    {
        _tsExporter = new Mock<TsExporter>().As<ITsExporter>();

        //This is calling the real code which is good
        _tsExporter.Setup(x => x.Export(It.IsAny<TsFileModel>(), It.IsAny<string>()))
            .CallBase();
        //but this is calling the real code too, and I was expecting not to
        //call it and return the mock instead...
        _tsExporter.Setup(x => x.RetrieveTranslations(It.IsAny<DataTable>(),
                It.IsAny<string>(), It.IsAny<string>()))
            .Returns(new DataTable());
    }

    [Test]
    public void Test()
    {
        _tsExporter.Object.Export(new TsFileModel(), "");
    }
}

What am I missing ?

Thank you !

  • You are using `Mock`s wrong. Take a look at [this blog](https://www.wiliam.com.au/wiliam-blog/mocking-objects-for-unit-testing) to understand how to design your code for unit tests and mocking. Basically you inject external dependencies (`ITsExporter`) and the parent class will call your mocked object instead of the real object. – Simply Ged May 16 '19 at 05:45
  • I think that's not the case here unfortunately, correct me if I am wrong: I don't have any external dependencies. There is only this class TsExporter which implements and interface ITsExporter. The method Export() will be called from somewhere else (with some parameters) and the RetrieveTranslations() is called internally by the Export() method and this creates a db connection, and that's why I want to mock this method, it will be tested at the integration testing where we are working with the database. I hope this make sense. I don't want to mock the db connection or should I ? – Adrian Chiritescu May 16 '19 at 05:56
  • You are creating a db connection, so you have an external dependency. In order to mock that external dependency, you should model your code in such a way you can mock that external dependency, i.e. mock the db connection (or the abstraction that you use to access the database). – oerkelens May 16 '19 at 06:14
  • Also, looking at your code, the setup for `Export` is pointless as all it does it `CallBase()`. You might as well remove that because `_tsExporter.Object.Export(...)` will call the real method anyway. You gain nothing by mocking it. And, when you move that, you can probably see why your mock of `RetrieveTranslations` isn't getting called? HINT: You are just calling the real class which has no knowledge of your mock :-) – Simply Ged May 16 '19 at 06:24
  • Thank you for your answers ! If I will remove that, it won't call the real code anymore, it will mock everything. – Adrian Chiritescu May 16 '19 at 06:30

2 Answers2

4

You should not be mocking the class that you are testing, but rather mock the dependencies of that class, to change the output they produce and how they influence the code that you are running. A unit test should test only a single logic bit of code.

Look at this simple tutorial on how to mock: https://developerhandbook.com/unit-testing/writing-unit-tests-with-nunit-and-moq/

UPDATE

I Do not think you should be mocking a DB Connection, either abstract out your class that accesses DB content to a repository and mock it.

Another question is what kind of a Db access you are using? EF? Dapper? There are ways of mocking those and testing how your class handles various returns from those.

For example EF:

How to mock EntityFramework Database created by codefirst strategy? and How are people unit testing with Entity Framework 6, should you bother?

UPDATE

You are correct in thinking that it is meant to call the real implementation or the base class implementation. However, it is not applicable in your case unless you are trying to write integration test. If you are writing Unit tests you should be testing a single unit of work independently of other class real output. What is a CallBase feature for I think is a different question. IN my understanding it is meant to call the class that you are inheriting from to test that functionality, but still you should not be testing it by mocking the class that implements it, if it is abstract class you should not be testing it by mocking the testing class otherwise you are testing a different class. Either change the class, either do not test it, or rework you original class to call that one and see the output of it. On top of that as far as I understand you are calling the base to mock connection string or sort of, this does not have an influence on the running code, or at least it should not as you are mocking the output anyway, otherwise this would be already integration testing.

Good article to read about it would be: http://www.codenutz.com/unit-testing-mocking-base-class-methods-with-moq/

vsarunov
  • 1,433
  • 14
  • 26
  • Great answer ! But why is moq having a CallBase feature if we shouldn't be mocking the classes that we are testing, what is its benefit then ? When should we use it ? Regarding the db access, we are using NHibernate for that. – Adrian Chiritescu May 16 '19 at 06:26
  • @AdrianChiritescu Updated. – vsarunov May 16 '19 at 06:44
  • I think moq is inheriting the mocked class and the base class would be our real class, and therefore CallBase which calls the real code but I am not sure, I will do some researching and come back ! – Adrian Chiritescu May 16 '19 at 06:52
  • If I would make the method RetrieveTranslations() virtual, the mock is working fine and the real code will be executed for the entire class excepting the RetrieveTranslations() method which has a mocked return. So all I was missing is that the method must be virtual in order to accomplish this behavior. – Adrian Chiritescu May 16 '19 at 07:03
  • 1
    I have found that CallBase() is usually meant to test abstract classes @vsarunov – Adrian Chiritescu May 16 '19 at 07:18
0

The mocking was fine.

What I was missing was to make the RetrieveTranslations() virtual in the class under testing.

So in this way, the real code is executed excepting the RetrieveTranslations() method which will return whatever the mock is telling it to return.

This is not a good way to do it, as people mentioned it in the comments too, we shouldn't mock the class under test but if someone needs this for some reason, here it is how you can do it.

PS: I refactored the class so that I don't have to mock this class but its dependencies instead, and inject them where needed.