2

I've tried couple of approaches to unit test the REST service but to no avail.

  1. Followed this post, by creating DirectServiceClient but "method is not implemented" exception is raised.

  2. Directly instantiated the web service and called the Any() method, it worked but it hits the DB. I've initialized the connection in the setup as below. But I am not knowing how to Mock connection object and set in-memory customer object.

    _dbConnection = new OrmLiteConnectionFactory(TestConfig.ConnectionString,SqlServerDialect.Provider).OpenDbConnection();

Could anyone provide some inputs on how to write unit tests in this kind of scenario.

Customer Service

public class CustomerService : Service
{
   private readonly IDbConnection _dbConnection;

   public CustomerService(IDbConnection dbConnection)
   {
       _dbConnection = dbConnection;
   }

   public object Any(CustomerRequest request)
   {
      if (request.id == null)
      {
          throw new ArgumentException("id is required");
      }

      var customer = _dbConnection.QueryDapper<Customer>("getCustomer",new {@id=request.id}).ToList();

      return customer;
   }
}

Request

[Route("/customers")]
[Route("/customer/{id}")]
public class CustomerRequest : IReturn<Customer>
{
    public string id { get; set; }
}
Community
  • 1
  • 1
Sunny
  • 4,765
  • 5
  • 37
  • 72

2 Answers2

3
  1. I believe DirectServiceClient is used more for integration tests (ie end to end).

  2. Use a mocking tool to stub out the Database. After all, for this unit test you only want to test the 'Any' method:

[Test]
public void Any_CalledWithoutId_ExpectThrowArgumentException()
{
  var db = MockRepository.GenerateStub<IDbConnection>();
  var request = new CustomerRequest();
  var service = new CustomerService(db);

  Assert.Throws<ArgumentException>(() => service.Any(request));
}

Thats roughly it. (sorry abt formatting .... the SOO formatter is not behaving, so I block quoted it)

ozczecho
  • 8,649
  • 8
  • 36
  • 42
  • is this the only test I can write for this method. I am sorry I am new to TDD, and how to check if properties are correctly mapped into the customerdto. I mean how to mock data from db. – Sunny Mar 26 '13 at 22:52
2

is this the only test I can write for this method.

ozczehco's answer will test the code path that throws the exception. If you want test the code path that moves past the exception you'll need to mock/stub the _dbConnection.QueryDapper call.

Below is expanding on ozczecho answer by adding a test 'Any_CalledWithAnId_ReturnsCustomer()' and includes all the 'ceremony'. I did modify a few things in the code you provided. Instead of mocking/stubbing the IDbConnection for the new test, I created an InMemoryTestDatabase just for testing. DON"T USE THIS AGAINST YOUR OWN DATBASE as it wipes the 'Customer' table for the test.

[TestFixture]
public class CustomerServiceTest
{
    public IDbConnectionFactory InMemoryTestDatabase;

    [SetUp]
    public void SetUp()
    {
        InMemoryTestDatabase = new OrmLiteConnectionFactory("c:\\testData.db", SqliteDialect.Provider);
    }

    [Test]
    public void Any_CalledWithoutId_ExpectThrowArgumentException()
    {
        var db = MockRepository.GenerateStub<IDbConnection>();
        var request = new CustomerRequest();
        var service = new CustomerService(db);

        Assert.Throws<ArgumentException>(() => service.Any(request));
    }

    [Test]
    public void Any_CalledWithAnId_ReturnsCustomer()
    {
        //Arrange your data
        long requestId;
        using (var con = InMemoryTestDatabase.OpenDbConnection())
        {
            con.CreateTable<Customer>(true); //Force drop to create clean table and data
            con.Insert<Customer>(new Customer { FirstName = "Johnny", LastName = "Test"});
            requestId = con.GetLastInsertId();
        }

        //Act
        var request = new CustomerRequest {id = (int)requestId};
        var service = new CustomerService(InMemoryTestDatabase.OpenDbConnection());
        var result = (Customer)service.Any(request);

        //Assert
        Assert.AreEqual(requestId, result.Id);
        Assert.AreEqual("Johnny", result.FirstName);
    }
}


[Route("/customers")]
[Route("/customer/{id}")]
public class CustomerRequest : IReturn<Customer>
{
    public long id { get; set; }
}

public class Customer
{
    [AutoIncrement]
    public long Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class CustomerService : ServiceStack.ServiceInterface.Service
{
    private readonly IDbConnection _dbConnection;

    public CustomerService(IDbConnection dbConnection)
    {
        _dbConnection = dbConnection;
    }

    public object Any(CustomerRequest request)
    {
        if (request.id == null)
        {
            throw new ArgumentException("id is required");
        }

        var customer = _dbConnection.QueryDapper<Customer>("Select * From Customer Where Id = @id", new { id = request.id }).ToList();

        return customer.FirstOrDefault();
    }
}
paaschpa
  • 4,816
  • 11
  • 15
  • Thanks for your reply! I am calling a stored procedure that are in different DB's to populate the DTO's, so how to do this with in-memory database. – Sunny Mar 28 '13 at 00:25
  • I don't think Sqlite supports stored procedures - http://stackoverflow.com/questions/3335162/creating-stored-procedure-and-sqlite. Instead of an In-Memory database, you could create a database only for testing. – paaschpa Mar 28 '13 at 03:17