0

I am testing a class that has a method which is private and is internally called from a public method. I want to be able to fake this test method so that the actual method is never called.

public class Service
{
    public int MethodA(int a)
    {
        SaveToDB(a);
        if (validate())
        {
                return a * 5;
        }
        else 
        {
            return 0;
        }
    }

  private bool validate(int a)
  {
        if (a > 100)
          return true;
        else 
          return false; 
   }

    private bool SaveToDB()
    {
     // some logic to save to the database..
     return true;
    }
 }

[FixtureTest]
public ServiceTest
{
//assuming we are using nunit and fakeiteasy..
[Test]
public void MethodA_Should_Return_Zero_when_Provided_100()
{
    var fakeService = new Service;
    var result = fakeservice.MethodA(101);
    // I want to avoid the call SaveToDB() in the test how do I go about doing this..

 //if this was a public method I could create a test stub and test like with a statement like 
 A.call(() => ServiceA.SaveToDB().Return())
// however this is a private function what should I do???
}
}
hussian
  • 399
  • 6
  • 19
  • 2 problems here. 1) you can't access private methods outside the scope of the class. So there's no way to test / mock a private method. 2) You can't mock the db call as it's part of the service layer. If you separate your service and DAL layers this will be easier to mock. – Barry O'Kane Aug 16 '18 at 15:32
  • My first idea would be dependency injection. If the Service would be injected with some IDbSaver, which performs the saving to DB, your test could easily inject a fake one. – Fildor Aug 16 '18 at 15:32
  • You could do it the other way around. Test the private functions (via reflection) to prove they work, then, test the public function. It's not nice, and using DI would be cleaner and better, but sometimes dirty is the only way (just make sure you wipe your hands when you turn off the computer). – Neil Aug 16 '18 at 15:35

1 Answers1

0

The simplest answer is to make SaveToDB protected virtual and create a testable derived class in the test project.

public class FakeTestService : Service
{
    ...

    protected override bool SaveToDB()
    {
        // do nothing

        return true;
    }
}

Use FakeTestService in your tests, and the "real" MethodA will execute but SaveToDB will do nothing. The real answer, though, is to use some form of inversion of control to inject an interface to your DB that can be mocked via a mocking library.

public class Service
{
    public int MethodA(int a)
    {
        DatabaseThinger.SaveToDB(a);
        if (validate())
        {
            return a * 5;
        }
        else 
        {
            return 0;
        }
    }

    private IDatabaseThinger DatabaseThinger;

    public Service(IDatabaseThinger databaseThinger)
    {
        DatabaseThinger = databaseThinger;
    }
}

So move the database functionality out of the class and put it behind an interface instead. You can then inject an implementation of IDatabaseThinger of your choosing when testing that won't actually connect to a DB.

Paul Abbott
  • 7,065
  • 3
  • 27
  • 45