简体   繁体   中英

Moq Framework to unit test a method that returns a task

I am new to this MOQ framework and honestly having a hard time with having to get my unit test to run. Basically, I have a C# application which basically does some uploads to APIs using PostAsync.

Now, since I can't (and should not) call the API during my unit test (as otherwise it would be an integration test), I added a wrapper method around it and allowing that method to return true by mocking it. But no matter what I do, it is returning false. I have gone through SO questions, but I am not sure what am I missing. I haven't used interfaces but am using classes with virtual methods.

Here is my sample code that I would want to test

public async Task<bool> CreateNoteBookDirectory (string url ,string bearertoken, JavaScriptSerializer jser,RestPostClass rest)
        {
            NoteBookDirectory jsnbdir = new NoteBookDirectory();
            jsnbdir.path = "/JobNotebooks/ClientScoreDataInput";

            var directorycreate = jser.Serialize(jsnbdir);
            var content = new StringContent(directorycreate, Encoding.UTF8, @"application/json");


            bool result=await rest.HttpPost(url, content, bearertoken);

            return result;
        }

This method is in the main class.

The RestPostClass class has the virtual method HttpPost, whose skeleton is somewhat like this

 public async virtual Task<bool> HttpPost(String url, StringContent content, string bearertoken)
        {
            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", bearertoken);
            // Add an Accept header for JSON format.
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(@"application/json"));
            var postresult = await client.PostAsync(url, content);
            bool result = parseResponse(postresult);
            return result;
        }

Now, in my unit test, I am trying to test the CreateNoteBookDirectory method and since do not want the post method to be called, mocking it.

Here is what I am doing in my sample unit test

 Mock<DataBricksRestPost> mock = new Mock<DataBricksRestPost>();
            mock.Setup(x => x.HttpPost("http://test.com", new StringContent("abc"), "token")).Returns(Task.FromResult(true));
            Program prog = new Program();
            var jser = new JavaScriptSerializer();
            bool result= await prog.CreateNoteBookDirectory("http://test.com", "token", jser, mock.Object);
            Assert.IsTrue(result, "Test failed");     

It keeps returning false because apparently the mocking does not really happen properly.

What am I missing?

Any questions and I will try my best to clarify.

PS: I have used the existing the "program" class as I am basically starting.

Mock returns false , because when you call HttpPost parameters don't match with ones that were set up. The second parameter is different.

You can set up mock like that:

mock
    .Setup(x => x.HttpPost("http://test.com", It.IsAny<StringContent>(), "token"))
    .Returns(Task.FromResult(true)); //or .ReturnsAsync(true);

It tells mocking framework, that second parameter can be any object of type StringContent .

Docs can be found here: https://github.com/Moq/moq4/wiki/Quickstart#matching-arguments

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