Solved

Unit testing, moq, best practices

Posted on 2016-10-14
7
58 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 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
Master Your Team's Linux and Cloud Stack

Come see why top tech companies like Mailchimp and Media Temple use Linux Academy to build their employee training programs.

 
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

DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Hey!! 5 33
Batch file or script with password 22 41
Hey!!!! 1 20
I've got an interview this morning and I want to sound intelligent... 4 49
Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the re…
The article shows the basic steps of integrating an HTML theme template into an ASP.NET MVC project
This Micro Tutorial will teach you how to censor certain areas of your screen. The example in this video will show a little boy's face being blurred. This will be demonstrated using Adobe Premiere Pro CS6.
In a recent question (https://www.experts-exchange.com/questions/28997919/Pagination-in-Adobe-Acrobat.html) here at Experts Exchange, a member asked how to add page numbers to a PDF file using Adobe Acrobat XI Pro. This short video Micro Tutorial sh…

785 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