Solved

Unit testing, moq, best practices

Posted on 2016-10-14
7
156 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
Technology Partners: 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!

 
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

For those of you who don't follow the news, or just happen to live under rocks, Microsoft Research released a beta SDK (http://www.microsoft.com/en-us/download/details.aspx?id=27876) for the Xbox 360 Kinect. If you don't know what a Kinect is (http:…
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…
This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.

630 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