Solved

Unit testing, moq, best practices

Posted on 2016-10-14
7
28 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
  • 5
  • 2
7 Comments
 
LVL 74

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 74

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
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 
LVL 74

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 74

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 74

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

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

In my previous article (http://www.experts-exchange.com/Programming/Languages/.NET/.NET_Framework_3.x/A_4362-Serialization-in-NET-1.html) we saw the basics of serialization and how types/objects can be serialized to Binary format. In this blog we wi…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
This video discusses moving either the default database or any database to a new volume.
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

757 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

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now