When testing units of measure, is validation used to indirectly test the ok method in this example?

I would like to check FindPolicyToBeResent () in the following code snippet. I have several options available, but would like to know how someone else approaches this situation if my approach, i.e. Is the last option ok?

  • Make FindPolicyToBeResent () public. This is not an option as it provides an implementation for the sole reason for testing and makes the interfaces confusing.
  • Unit test using only the public API, but this can be tricky since I never expand the collection that I filter directly in the return statement and cannot do it for security reasons. This would mean that I only had limited tests.
  • Normally I would split the code into a new object in this situation, but it doesn't feel good in this case, I can't foresee this filter being reused elsewhere in the system, so it wouldn't be any better than the public method, and before than someone will hit me with one stick with responsibility (that would be justified), coding is a balancing act, I feel like it would violate the Keep It Simple principle. It's just like making a class to serve the test rather than having a separate single responsibility. Plus it leads to bloating of files and classes.
  • I could make the code an extension of the IEnumerable method that would make it testable, but again I can't get this filter to be used anywhere else, so it would make more sense if it stayed in this class
  • The latter option and preferable, but can be seen as a little hacky, checking the document layoutResenderRepository.CanPolicyBeResent (policy.Id) further down the code using verify () to see how long it took. I'm not sure if this is a good idea? Thoughts?

My preference is for the latter option, but it feels a little messy, I have an example below

public class DocumentResendService : IDocumentResendService
{
    #region Member Variables
    ...
    #endregion


    #region Constructors
    ...
    #endregion


    #region Accessors
    ...
    #endregion

    #region Methods
    public IDocumentResendResponse ResendDocuments()
    {
        if (!IsInputsValid())
        {
            return response;
        }


        RecordRequestAttempt();

        if (RequestLimitIsReached())
        {
            return response;
        }


        FindPolicyToBeResent();


        if(PolicyCanNotBeResent())
        {
            return response;
        }

        RequestDocumentToBeResent();

        return response;
    }


    private bool IsInputsValid()
    {
        ..
    }


    private void RecordRequestAttempt()
    {
        ...
    }


    private bool RequestLimitIsReached()
    {
        ...
    }

    // I want to test this method which basically just filters the policies
    private void FindPolicyToBeResent()
    {
        var allPolicies = policyDocumentRepository.GetPolicy(AgentCode, Email, PostCode, SearchDate, BirthDate);

        policies = allPolicies.Where(currentPolicy => currentPolicy.IsActive() || currentPolicy.IsInTheFuture());

        if (policies.Count() == 0 )
        {
            policies = allPolicies.FilterToPolicyThatHasEndedMostRecently();          
        }
     }


    private bool PolicyCanNotBeResent()
    {
        if (policies == null || !policies.Any())
        {
            response.Add(ErrorCode.PolicyCanNotBeFound);

            return true;
        }

        foreach (var policy in policies)
        {
           // I could mock this line and use a verify here which policy id are passed in
            if (documentResenderRepository.CanPolicyBeResent(policy.Id) == false)
            {
                response.Add(ErrorCode.UnableToResendDocument);
            }  
        }

        return response.Errors.Any();
    }


    private void RequestDocumentToBeResent()
    {
        ...
    }

    #endregion
}

      

Here is a unit test solution for the last option, but

[TestFixture]
public class FindPolicyToBeResentTest : DocumentResenderTestsBase
{
    private readonly List<Policy> allPolicies = new List<Policy>();

    public FindPolicyToBeResentTest()
    {
        var day = -250;

        for (int i = 1; i < 6; i++)
        {
            var policy = new Policy
            {
                Id = i,
                StartDate = DateTime.Now.AddDays(day)
            };
            day = day + 100;
            policy.EndDate = DateTime.Now.AddDays(day);
            allPolicies.Add(policy);
        }
    }

    private void SetUpDocumentResender(IEnumerable<Policy> policies)
    {


        SetUpObjectDefaultsForDocumentResenderCreation();

        policyRepositoryMock.Setup(y => y.GetPolicy(It.IsAny<string>(),
                                                    It.IsAny<string>(),
                                                    It.IsAny<string>(),
                                                    It.IsAny<DateTime>(),
                                                    It.IsAny<DateTime>()))
            .Returns(policies);


        documentResendService = CreateDocumentResendService();

        SetDocumentResenderDefaults();
    }


    [Test]
    public void PoliciesThatAreNotActiveOrAreInThePastShouldBeFilteredOut()
    {
        SetUpDocumentResender(allPolicies);

        documentResendService.ResendDocuments();

        foreach (var policy in allPolicies)
        {
            if (policy.IsActive() || policy.IsInTheFuture())
            {
                documentResenderRepositoryMock.Verify(x => x.CanPolicyBeResent(policy.Id), Times.AtLeastOnce());
            }
            else
            {
                documentResenderRepositoryMock.Verify(x => x.CanPolicyBeResent(policy.Id), Times.Never());
            }
        }
    }

    [Test]
    public void IfNoPoliciesAreFoundThatAreSuitableForDocumentResendingThenGetThePolicyThatHasMostRecentlyExpired()
    {
        var unsuitablePolicies = allPolicies.Where(x => x.IsActive() == false && x.IsInTheFuture() == false).OrderBy(x => x.EndDate);

        var policyWithClosestToEndDateToNow = unsuitablePolicies.ToList().Last();

        SetUpDocumentResender(unsuitablePolicies);

        documentResendService.ResendDocuments();

        documentResenderRepositoryMock.Verify(x => x.CanPolicyBeResent(policyWithClosestToEndDateToNow.Id), Times.AtLeastOnce());

        foreach (var policy in allPolicies.Where(policy => policy != policyWithClosestToEndDateToNow))
        {
            documentResenderRepositoryMock.Verify(x => x.CanPolicyBeResent(policy.Id), Times.Never());
        }
    }
}

      

+3


source to share


2 answers


Testing private methods with a public method is fine. If your code is modular enough, there shouldn't be too much configuration code to get the right conditions for accessing your private method. If you find yourself setting up a lot of things just to get into your private method, chances are you are doing too much in one class.

In your case, I would be tempted to go with your point 3) and create a PolicyFinder: IPolicyFinder class. You may not need to reuse it right now, if your code will be much easier to modify in the future and make it easier to test both classes



(see http://en.wikipedia.org/wiki/Single_responsibility_principle )

edit: I haven't fully read your point 3), so sorry for stumbling upon the sole responsibility;)

+5


source


You can mark methods, not private ones, and then use InternalsVisibleTo in the AssemblyInfo.cs file to allow unit test to access those internal methods. For example, this statement in the AssemblyInfo file for my OVReadySDK assembly:

[assembly: InternalsVisibleTo("OVReadySDKUT, PublicKey=002400000480...5baacad")]

      



allows the test methods in my unit test assembly, OVReadySDKUT, to access classes and methods in the OVReadySDK as if the test methods were the same.

You can find many examples of this technique by searching for "InternalsVisibleTo unit test". Note that if your assembly is signed, you need to provide a public key argument in the statement InternalsVisibleTo

.

0


source







All Articles