lundi 27 juillet 2015

Unit Testing Principles and Approaches

Introduction

Recently I have moved from an environment where I am not unit testing, into one where I need to.

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.

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?

Code Sample

Imports NSubstitute
Imports NUnit.Framework

Namespace Services

    <TestFixture()>
    Public Class ImportantServiceTests

        <TestCase("userA")>
        <TestCase("userB")>
        Public Sub GetImportantItems_WithValidUser_ItemsForThatPerson(user As String)
            ' Arrange
            Dim importantService = New ImportantService()

            ''''''''''''''''''''''''''''''''''
            ''''''vvv Value Generation vvv''''
            Dim importantItem = Substitute.For(Of IImportantItem)
            importantItem.Id.Returns(1)

            Dim subImportantService = Substitute.For(Of IImportantService)()

            subImportantService.GetImportantItems("userA").Returns(
                    New List(Of IImportantItem) From {importantItem}
                )

            subImportantService.GetImportantItems("userB").Returns(
                    New List(Of IImportantItem)
                )

            ''''''^^^ Value Generation ^^^''''
            ''''''''''''''''''''''''''''''''''

            ' Act
            Dim importantItems = importantService.GetImportantItems(user)

            ' Assert
            CollectionAssert.AreEqual(importantItems, subImportantService.GetImportantItems(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?

Footnote

I'm wanting to make the tests lean and independent as I can, so when new developers join the team it is easy and straightforward for them to pick up. As a result of this I have created this post, after searching around for similar questions and articles. I hope the question does not appear too broad, or not a good fit. I hope it will prove useful for others having a problem with this topic.

Aucun commentaire:

Enregistrer un commentaire