Solved

Unit testing, moq, best practices

Posted on 2016-10-14
7
112 Views
Last Modified: 2016-10-14
I have a setting repository that contains application settings that are stored in the database.
I currently have no unit test code coverage. The IService interface only contains one method for Get()
Get() returns a collection of Setting.

1. What should I be testing?
2.. What should I be naming the tests?

    public class SettingServiceTest
    {
        private Mock<ISettingRepository> mockRepository;
        private ISettingService service;

        [TestInitialize]
        public void Inititalize()
        {
            mockRepository = new Mock<ISettingRepository>();
            service = new SettingService(mockRepository.Object);
        }

        [TestMethod]
        public void Test_Get_Settings()
        {
            mockRepository
                 .Setup(x => x.Get())
                 .Returns(It.IsAny<List<Setting>>);

            var result = service.Get();
            mockRepository.Verify(x => x.Get());
        }
    }

Open in new window

0
Comment
Question by:JRockFL
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 2
7 Comments
 
LVL 75

Assisted Solution

by:käµfm³d 👽
käµfm³d   👽 earned 500 total points
ID: 41844050
What should I be testing?
Your service layer. You can also test your UI layer via coded-UI test. I find those tests harder to work with and modify compared to regular unit tests. Testing your database would be covered by an integration test.

What should I be naming the tests?
I prefer the convention:

System Under Test____Condition____Expected Result

In this way, when a test fails, you can easily see within the Test Explorer what is failing. Also, developers coming behind you can see what the test *should* be doing.
0
 
LVL 8

Assisted Solution

by:JRockFL
JRockFL earned 0 total points
ID: 41844066
Thank you for your reply. Yes, I agree that I should be testing the service layer and the naming convention.
I was looking for the specific tests I should be doing against this service layer for settings.

Test_Get_Settings_Returns_List_Of_Settings
Would this be an appriopate test name?
Would there be value to this test? How else should I test it?
0
 
LVL 75

Accepted Solution

by:
käµfm³d   👽 earned 500 total points
ID: 41844154
Would this be an appriopate test name?
IMO, no. You don't want to test the data type that's being returned. What if you change from a List<string> to an integer? Now you have to go and rename that test (and maybe others).

In this specific case, there's not really much to test. Your method simply invokes the database. This method is effectively a wrapper around the data layer (since you don't have any business logic here). You  *could* test that you are invoking the database method--which you could do using Moq's Verify methods, as you are already doing. Having said that, many people would consider that to be testing an implementation detail, which they would advise against. The danger with tests of this nature is that if the implementation changes, then the corresponding tests have to change as well. (I'm personally on the fence as to whether or not this is a good or a bad thing.)
0
SharePoint Admin?

Enable Your Employees To Focus On The Core With Intuitive Onscreen Guidance That is With You At The Moment of Need.

 
LVL 75

Assisted Solution

by:käµfm³d 👽
käµfm³d   👽 earned 500 total points
ID: 41844158
I would write the test thus:

public class SettingServiceTest
{
    private Mock<ISettingRepository> mockRepository;
    private ISettingService service;

    [TestInitialize]
    public void Inititalize()
    {
        mockRepository = new Mock<ISettingRepository>();
        service = new SettingService(mockRepository.Object);
    }

    [TestMethod]
    public void Get_Called__Always__ISettingRepository_Get_Called()
    {
        // Arrange
        mockRepository
             .Setup(x => x.Get())
             .Returns(It.IsAny<List<Setting>>);

        // Act
        var result = service.Get();
        
        // Assert
        mockRepository.Verify(x => x.Get());
    }
}

Open in new window


I explicitly include "Arrange", "Act", and "Assert" comments to make it clear to others how the test is structured, including where each section begins/ends. In this case, because of the aforementioned wrapper behavior, I wouldn't have a condition, and I would simply denote the condition as "Always". This hopefully makes it clear what the intent of the code and/or test is.
0
 
LVL 75

Assisted Solution

by:käµfm³d 👽
käµfm³d   👽 earned 500 total points
ID: 41844160
P.S.

In the name, I don't include "SettingService" in the System Under Test (sut) because the class itself denotes this. All tests within this class should correspond to the SettingService. Therefore, each method's sut is simply the method being invoked. (I usually quantify a "unit" to be a method, but this is not a hard and fast rule. A unit could be more than one method, or even an entire class. You have to determine what is a sensible "unit" for your environment.)
0
 
LVL 75

Assisted Solution

by:käµfm³d 👽
käµfm³d   👽 earned 500 total points
ID: 41844167
P.P.S.

And I just realized that you have the service scoped to the class. I would not suggest this. If your service doesn't maintain any state internally (i.e. private fields), then you are probably safe. But it is very easy for another developer to come behind you, add some state, and suddenly 100 tests are broken and you have no idea why. Also, you want your unit tests to be independent of each other. This ensures no side effects.

Tests typically run pretty fast (because you will be mocking out database, web service, and other dependencies). There is no reason not to new up an instance of the service per test. Worry about refactoring the tests later if you encounter performance issues.

Same thing with the mock. You don't want to inadvertently have one mock object's state affecting a different test.

e.g.

public class SettingServiceTest
{
    [TestMethod]
    public void Get_Called__Always__ISettingRepository_Get_Called()
    {
        // Arrange
        Mock<ISettingRepository> mockRepository = new Mock<ISettingRepository>();
        ISettingService service = new SettingService(mockRepository.Object);

        mockRepository
             .Setup(x => x.Get())
             .Returns(It.IsAny<List<Setting>>);

        // Act
        var result = service.Get();
        
        // Assert
        mockRepository.Verify(x => x.Get());
    }
}

Open in new window

0
 
LVL 8

Author Comment

by:JRockFL
ID: 41844502
Thank you for much. That has been very helpful.
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This document covers how to connect to SQL Server and browse its contents.  It is meant for those new to Visual Studio and/or working with Microsoft SQL Server.  It is not a guide to building SQL Server database connections in your code.  This is mo…
Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
Finding and deleting duplicate (picture) files can be a time consuming task. My wife and I, our three kids and their families all share one dilemma: Managing our pictures. Between desktops, laptops, phones, tablets, and cameras; over the last decade…

752 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question