简体   繁体   中英

Unit testing MVC Controller making calls to a static library calling external API

Good day,

I am confused about unit testing the following:

1. MVC Controller:

[HttpGet]
public async Task<PartialViewResult> DoExternalCallsAsync()
{
    var model = new MyModel();

    await MyStaticLibrary.DoExternalWorkAsync(Server.MapPath("~\\") + "WorkSource.txt", model);

    return PartialView("_MyResults", model);
}

2. Static library:

public static async Task DoExternalWorkAsync(string sourcePath, MyModel model)
        {
            var externalCalls =
                System.IO.File.ReadAllLines(sourcePath)
                .Where(line => (!string.IsNullOrEmpty(line) && line.First() != '#'))
                .Select(p => DoExternalCall(p, model));

            await Task.WhenAll(externalCalls);


        }



 private static async Task DoExternalCall(string urlPath, MyModel model)
            {
                var result = await GetExternalApiResultAysnc(urlPath);

                // some code here...



                return;
            }

Basically, all that the controller does is call an external API, which does some work and returns a result or throws an error.

There are no interfaces or abstract classes with the external Api.

How do I go about unit testing this? NB I am not at liberty to change the design of the external Api.

Thanks,

Using static classes or methods in your code makes that code hard to properly unit test. See Is static universally “evil” for unit testing and if so why does resharper recommend it? , Static class/method/property in unit test, stop it or not , When to use static classes in C# .

Wrap the static API call class into an instance class with an interface:

public interface IMyLibrary
{
    Task DoExternalWorkAsync();
}

public class MyStaticLibrary : IMyLibrary
{
    public async Task DoExternalWorkAsync(string sourcePath, MyModel model)
    {
        return await MyStaticLibrary.DoExternalWorkAsync(sourcePath, model);
    }
}

Then you can inject an instance into the controller's constructor .

Because the only thing that should be unit tested in this controller action method:

  • Does the code call the library with the proper arguments?
  • Does the method return the proper object?

During testing, you can inject a mocked IMyLibrary in the controller and verify that the controller correctly calls the mock, and you can verify that the result is a PartialViewResult containing whatever it should contain.

The library is an implementation detail of performing some unit of work. It should be abstracted out completely. If you want to run integration tests , that's a different style of testing completely.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM