-1

I have a class that implements DocRaptor's pdf creator

public class PdfCreator {
  public byte[] createPdf(string html){
      int tryCount = 3;
      while(tryCount > 0) {
          try {
            Configuration.Default.Username = "YOUR_API_KEY_HERE"; // this key works for test documents
            DocApi docraptor = new DocApi();

            Doc doc = new Doc(
                // create a new doc object
            );

            AsyncDoc response = docraptor.CreateAsyncDoc(doc);

            AsyncDocStatus status_response;

            Boolean done = false;

            while(!done) {
                // Mocked this but it's getting ovewritten with a different StatusId
                status_response = docraptor.GetAsyncDocStatus(response.StatusId);

                Console.WriteLine("doc status: " + status_response.Status);
                switch(status_response.Status) {
                case "completed":
                    done = true;
                    byte[] doc_response = docraptor.GetAsyncDoc(status_response.DownloadId);
                    File.WriteAllBytes("/tmp/docraptor-csharp.pdf", doc_response);
                    Console.WriteLine("Wrote PDF to /tmp/docraptor-csharp.pdf");
                    break;
                case "failed":
                    done = true;
                    Console.WriteLine("FAILED");
                    Console.WriteLine(status_response);
                    break;
                default:
                    Thread.Sleep(1000);
                    break;
                }
            }
        } catch (DocRaptor.Client.ApiException error) {
            if (--tryCount == 0) throw;
        }
      }
    }
  }
}

In my test, I'm trying to force it to fail and throw exception in the catch block by mokcing the GetAsyncDocStatus call to return a status of failed

_docRaptorService.Setup(p => p.GetAsyncDocStatus(It.IsAny<string>())).Returns("failed");

var docRaptor = new PdfCreator();

string html = $"<html><body><h1>Hello World!</h1></body></html>";

byte[] doc = docRaptor.createPdf(html);

_docRaptorService.Verify(p => p.GetAsyncDocStatus(It.IsAny<string>()), Times.Once);

But when I run the test the test fails saying the method was not called. And if I run the test in debug mode, the GetAsyncDocStatus returns completed instead of failed, which makes me think the class is not using the mocked version of the method. How can I solve this?

blankface
  • 5,757
  • 19
  • 67
  • 114
  • is `GetAsyncDocStatus` virtual? – Daniel A. White May 11 '20 at 02:10
  • No it's not virtual – blankface May 11 '20 at 02:11
  • make it virtual that way moq can do its thing. – Daniel A. White May 11 '20 at 02:11
  • You're instantiating `docraptor` in the method you're testing. So the mock instance you're creating isn't being used. Can you show the entirety of the class and the test? – devNull May 11 '20 at 02:13
  • @devNull Whatever I posted is the full version of the class/test – blankface May 11 '20 at 02:14
  • 1
    You'll need to actually use the mock instance of `DocApi` in your method. Which is usually done through dependency injection. The SO post above describes it more – devNull May 11 '20 at 02:18
  • Ah alright. So I should use DI and use the IDoc interface instead of instantiating the `DocApi` class. Will give it a go and let you know how it goes. – blankface May 11 '20 at 02:20
  • @devNull That worked, but even when it hits the `failed` state, it's still not going to the `catch` block. I think I need to simulate a timeout for it to enter that block. Any ideas? – blankface May 11 '20 at 02:28
  • @ZeroDarkThirty well you don't manually throw an exception in the "failed" case, so I wouldn't expect the catch block to be hit. It sounds like you just want to mock an exception be thrown from `GetAsyncDocStatus`. If so, you can see [this post](https://stackoverflow.com/a/10323930/5803406) on how that's done – devNull May 11 '20 at 02:40
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/213588/discussion-between-zerodarkthirty-and-devnull). – blankface May 11 '20 at 04:01

1 Answers1

0

The below implementation is working fine for me. Removed some parts of the code as the intention here is just to make sure the mock is working as expected. Used method injection for Dependency Injection, any type of DI can be used like constructor, property etc.

public class PdfCreator
{
    public byte[] CreatePdf(string html, IDocApi docraptor)
    {
        try
        {           

            Boolean done = false;

            while (!done)
            {
                // Mocked this but it's getting ovewritten with a different StatusId
                var status_response = docraptor.GetAsyncDocStatus("testInput");

                Console.WriteLine("doc status: " + status_response);
                switch (status_response)
                {
                    case "completed":
                        done = true;
                        byte[] doc_response = docraptor.GetAsyncDoc("DownloadId");
                        File.WriteAllBytes("/tmp/docraptor-csharp.pdf", doc_response);
                        Console.WriteLine("Wrote PDF to /tmp/docraptor-csharp.pdf");
                        break;
                    case "failed":
                        done = true;
                        Console.WriteLine("FAILED");
                        Console.WriteLine(status_response);
                        break;
                    default:
                        Thread.Sleep(1000);
                        break;
                }
            }
        }
        catch (Exception)
        {
            throw;
        }

        return new byte[1];
    }
}

public interface IDocApi
{
    string GetAsyncDocStatus(string docId);
    byte[] GetAsyncDoc(string downloadId);
}

public class DocApi : IDocApi
{
    public byte[] GetAsyncDoc(string downloadId)
    {
        throw new NotImplementedException();
    }

    public string GetAsyncDocStatus(string docId)
    {
        return "completed";
    }
}

In unit test mocked the IDocApi interface and injected it through the method.

 [TestClass]
public class UnitTest1
{
    [TestMethod]
    public void CreatePdfMethodGetAsyncDocStatusShouldReturnFailed()
    {
        Mock<IDocApi> mockDocApi = new Mock<IDocApi>();

        mockDocApi.Setup(m => m.GetAsyncDocStatus(It.IsAny<string>())).Returns("failed");

        PdfCreator sut = new PdfCreator();

        sut.CreatePdf("dummyHtml", mockDocApi.Object);

        //not asserting 
    }
}

Working screenshot enter image description here

ghosh-arun
  • 51
  • 4