How to unit test service that is using PetaPoco.Database
Asked Answered
C

2

8

I am using PetaPoco on my current project as a micro ORM and i must say that i like it. However, i found myself struggling with simple scenario - unit testing services that use PetaPoco.Database

public class MyService : IMyService
{
    private readonly PetaPoco.Database _database;

    public MyService(PetaPoco.Database database)
    {
        _database = database;
    }

    public void SaveSomething(MyObject myObject)
    {
        //...custom logic
        _database.Save(myObject);
    }
}

I am using IoC (Castle.Windsor) for injection of both IMyService and PetaPoco.Database wherever needed.

Now, when i try to unit test my service i am unable to properly mock stub PetaPoco.Database in order to verify that the Save method was properly invoked. I am using NUnit and Rhino.Mocks for unit testing and mocking.

[TestFixture]
public class MyServiceTests
{ 

    private PetaPoco.Database _database;

    [SetUp] 
    public void SetUp()
    {
        _database = MockRepository.GenerateMock<Database>("");
    }

    [Test]
    public void ShouldProperlySaveSomething()
    {
        //Arrange
        var myObject = new MyObject();
        _database.Expect(db => db.Save(Arg<MyObject>.Is.Anything));
        var myService = new MyService(_database);

        //Act
        myService.SaveSomething(myObject);

        //Assert
        _database.VerifyAllExpectations();   
    }

}

I am aware that this can be solved if i extract an Interface from PetaPoco.Database and do the mocking against it, or by virtualizing PetaPoco's methods that i want to mock, but the point is that i don't want to make changes to PetaPoco at all.

Is this doable?

Cottony answered 26/5, 2012 at 13:37 Comment(0)
G
4

My branch located here: https://github.com/schotime/PetaPoco already has an interface defined for the Database class.

Also there is my new Fork https://github.com/schotime/NPoco or NPoco on nuget which has the same api.

I would use one of these. ;)

Grandniece answered 28/5, 2012 at 8:36 Comment(10)
Great job @Schotime, that's exactly what i needed! I am curious though, have you tried to create pull requests to the original codebase?Cottony
Many a time, but I have lots more features as a part of the library now, with lots of bug fixes so they're almost two separate now.Grandniece
Is all features of petapoco supported(such as templates) or is there stuff missing? It seems like your fork also does what this plugin does PetaPoco.RelationExtensions. Are you using the same code? I am wondering as you don't see to have any documentation on some of your features so hoping I can use examples from other existing plugins.Lashundalasker
@Lashundalasker What documentation do you need? I have started some here: github.com/schotime/NPoco/wikiGrandniece
I don't see any documentation for any of the items in the extra section.Lashundalasker
@Lashundalasker so what doco do you need and I'll start with it.Grandniece
I am not getting how to One-to-Many query helpers. If you could start with this that would be great.Lashundalasker
@Grandniece - I see you also wrote PetaPoco.RelationExtensions extension. Has this been merged with npoco?Lashundalasker
@Grandniece - See my post here #13020125 for the problems I am having with itLashundalasker
Yes...it has been merged with NPocoGrandniece
Z
1

You are already abstracting interactions with PetaPoco.Database using the IMyService interactions, so why do you need another abstraction for? With your current approach you should be able to test interactions with the database using IMyService, e.g.

public class AuthenticationService 
{
    private IMyService myService;

    public AuthenticationService(IMyService service) 
    {
        ...
    }

    public void Authenticate(string username, string password)
    {
       var user = myService.GetUser(username); // <-- Hits the database
    }
}

and to test it you just mock interactions using a mock/stub of IMyService.

Now regarding your original solution, if PetaPoco public methods are not virtual, I'd fork it, fix the code and send them a pull request. Otherwise, your approach looks fine to me.

Zerline answered 28/5, 2012 at 3:23 Comment(2)
Thanks for your answer @Hadi. The point i am asking this question lies in the fact that i want to test MyService business logic in isolation, i.e. i do not want to hit the database, and at the same time i want to assure that database calls are triggered through PetaPoco. The way i see it, this is only possible by mocking PetaPoco.Database.Cottony
Forking the code, on the other hand seem like a good solution to me, i might give it a try.Cottony

© 2022 - 2024 — McMap. All rights reserved.