Skip to main content
8 of 8
replaced http://stackoverflow.com/ with https://stackoverflow.com/

Unit testing a service to return items from a database

I have been a developer for many years and get core development concepts, as well as unit testing ones such as DI/Ioc, Mocking etc. I also understand the values, importance of unit testing and writing good tests, as well as asking myself often: "What Would Roy Do?".

I am however slightly unsure on some approaches and principles to follow, and am not 100% sure of what I should be looking for; I am using NSubstitute and NUnit.

I am also using the EntityFramework with a class mapping over the entities to provide extra functionality and strongly-type it to other domain models; these properties have been excluded for brevity.

Is it considered correct to create an interface for my domain object? If I want to write unit tests against services which return a domain object, or check the values of these objects (when they return a list of domain objects) I think it seems right, but this article seems to suggest I shouldn't.

Questions

  1. How should the value generation be done? I'm not sure how we should make it react to different input parameters. I've implemented a way it could be done, but part of me feels this isn't right. What happens when I have more people added to it as I went to test, for example? Should I expand this section?

  2. Where should the value generation be done? Leaving it in the function feels wrong, but is clear as to how the values are generated/returned. Moving it to a function would make the test cleaner, and therefore easier to read (?), and usable in other tests? Or should I inject it (maybe with NInject?) but this would require the creation of another service?

Interface

    Public Interface IProductService
        Function GetProductItems(userAs String) As List(Of IProductItem)
    End Interface

Service Code

Namespace Services
    Public Class ProductService
        Implements IProductService

        Public Function GetProductItems(userAs String) As List(Of IProductItem) Implements IProductService.GetProductItems
            Dim result = New List(Of IProductItem)

            Using con As New ProductEntities(Settings.Settings.ConnectionString)
                For Each item In con.Product_Item.Where(Function(a) a.User.Equals(domainAndRacf, StringComparison.OrdinalIgnoreCase))
                    result.Add(New ProductItem(item))
                Next
            End Using

            Return result
        End Function
    End Class

Domain Model Interface

Public Interface IProductItem
    ReadOnly Property Id As Integer
End Interface

Domain Model

Namespace Classes
    Public Class ProductItem
        Implements IProductItem
        Private _entity As Product_Item

        Public ReadOnly Property Id As Integer Implements IProductItem.Id
            Get
                Return _entity.Id
            End Get
        End Property

        ## Constructors and other properties ommitted ##
   End Class
End Namespace

Test Sample

    Imports NSubstitute
    Imports NUnit.Framework
    
    Namespace Services
    
        <TestFixture()>
        Public Class ProductServiceTests
    
            <TestCase("userA")>
            <TestCase("userB")>
            Public Sub GetProductItems_WithValidUser_ItemsForThatPerson(user As String)
                ' Arrange
                Dim ProductService = New ProductService()
        
                ''''''''''''''''''''''''''''''''''
                ''''''vvv Value Generation vvv''''
                Dim prod = Substitute.For(Of IProductItem)
    
                Dim subProductService = Substitute.For(Of IProductService)()
    
                subProductService.GetProductItems("userA").Returns(
                        New List(Of IProductItem) From {prod}
                    )
    
                subProductService.GetProductItems("userB").Returns(
                        New List(Of IProductItem)
                    )
    
                ''''''^^^ Value Generation ^^^''''
                ''''''''''''''''''''''''''''''''''
    
                ' Act
                Dim prodItems = ProductService.GetProductItems(user)
    
                ' Assert
                CollectionAssert.AreEqual(prodItems, subProductService.GetProductItems(user))
            End Sub
    
        End Class
    End Namespace

Extension

An extension to the above (which I hope is still classed as related, due to following a similar theme of principles and approaches), is about testing against a database accessed through the EntityFramework DatabaseFirst.

There are other posts talking about mocking the entire framework, but this to me feels overkill. Is there a better way than creating hand-written substitutions for every single table and value within there?

I'm wanting to make the tests as lean and independent as I can, so when new developers join the team it is easy and straightforward for them to pick up.

askrich
  • 175
  • 6