Performing an ID check on a person and saving the result I'm just trying to understand and use unit tests, which from what I can tell is exposing the issues with my code.  A lot of what I do is MVC/WebAPI.  One of the big issues I come across is that my methods end up too long, doing too much, which makes it very difficult to test them. 

Description of what the code is for:

The code is taking a request to ID check a person, firstly I try to do this locally, reusing internal data (cheaper!). But if we don't have the information, we have to use an external web service.  I then return the result of whether the person is verified.

I create a log entry in a database, save that.  Then do a check, which is set against that previous entry.  Then return the result to the calling WebAPIController.

What I want: 

Here's is the current block I'm looking at, how could I improve it, what should I do differently?  I am a pragmatic man, but I know this can be a lot cleaner, however I'm unsure where to break it up.  Typically using a repository style.

I want to make it more testable and cleaner.  I hear about keeping to a few lines per method.  Also making sure it only does one thing.  But then I think about my code below and they are a series of conditions which are evaluated.  So I could break them up, but it wouldn't be for re-use at this point, they would only be called once.  Which at the moment doesn't make sense for me to do, but it leaves me with long methods.

public interface IInvestigationManager
{
    Task&lt;idResponseVM&gt; LogAndDoCheck(idRequestVM requestVM);
}


public class InvestigationManager : IInvestigationManager
{
    private readonly IIdentityAuthenticationRepository _identityAuthenticationRepository;

    public async Task&lt;idResponseVM&gt; LogAndDoCheck(idRequestVM requestVM)
    {
        // Initialise the identity check, log the request and get Id
        var newIdCheck = CreateIdentityCheckDM_FromRequestVM(requestVM);

        //Log the Request in the database; Marking it pending result
        _identityAuthenticationRepository.Add(newIdCheck);

        IdentityCheck latestLocalCheck = null;
        idResponseVM responseVM = new idResponseVM();

        try //database interactions.
        {
            await _identityAuthenticationRepository.SaveChangesAsync();

            // Check for existing local authentication
            latestLocalCheck = _identityAuthenticationRepository.LatestPreviousCheckWithinThreshold(newIdCheck);
        }
        catch (SqlException ex)
        {
            latestLocalCheck = null;
            responseVM.Errors.Add("SQL Server error", ex);
            // Divert to try external check
        }
        catch (Exception ex)
        {
            throw ex;
        }


        if (latestLocalCheck != null)
        {
            // Local check
            newIdCheck.IdentityServiceUsed = IdentityServiceUsed.Local;
            newIdCheck.ResultMatchIsValid = latestLocalCheck.ResultMatchIsValid;

            responseVM.ResultIsValidMatch = latestLocalCheck.ResultMatchIsValid;
            responseVM.Results = null;
        }
        else
        {
            try
            {
                // External Id Check
                var idResult = GetExternalCheckResponse(requestVM);
                var isMatch = idResult.matchlevel == enReportType.IndividualReport;

                newIdCheck.IdentityServiceUsed = IdentityServiceUsed.External;
                newIdCheck.ResultMatchIsValid = isMatch;

                newIdCheck.ResultMatchType = idResult.matchlevel.ToString();
                newIdCheck.ExternalSearchId = idResult.searchid;

                responseVM.ResultIsValidMatch = isMatch;
                responseVM.Results = idResult;

            }
            catch (WebException ex)
            {
                // Do other stuff as a backup plan
            }
            catch (Exception ex)
            {
                // Log
                throw ex;
            }
        }

        await _identityAuthenticationRepository.SaveChangesAsync();

        return responseVM;
    }
}
You can use a mocking library, like MOQ, to "intercept" calls to _identityAuthenticationRepository, thus removing the physical database from the equation. And you want to do this because you do not want to be testing the Web Service. All you care about is what this code does with a given returned response.

It is troubling that you have catch (SqlException ex) at this level. Why is this not done in the repository? Besides separation of concerns, it blows the whole idea of an abstract repository out of the water. 

Your concerns about "too long" methods seems arbitrary to me. LogAndDoCheck() may be "too long", but why? It's not so much "too long" as it is not understandable. Not without reading all the code carefully. It needs to be structured to express what's happening "at this level of abstraction". In other words, Your "Description of..." suggests what the method should look like:

 public ... LogAndDoCheck() {
     var identityThingy = VerifyLocally();

     if(!identityThing.Verified)
         identityThingy = VerifyRemotely();

     if(!identityThingy.Verified)
         throw new InvalidUserException(identityThingy.ToString());
 }


The method is not arbitrary made short. It's short because of the layering of abstract functional details.

It is also shorter because we got the repository out of the way. Of course you gotta call the repository eventually, but that method is now shorter too. And put the SqlException catching there too. That obviously is the best place to capture any available details like parameter values.

And exception handling might better be done by try { LogAndDoCheck(); } catch .... 

P.S.

Instead of setting the IdentityCheck to null, have a property or other way of asking the object if the identity is invalid. That way you have the properties it was built with - user entry stuff I imagine - at hand and that can be included in Exception.Data.