0

I would like to an async method "UpdateAsync" return custom exception message when PutAsync method is invoked. What I do now is mock the class which is PutAsync belong to, and then I setup the method and give the parameter. I also use Throws to custom exception message.

The problem is when I run this

var result = await this.repository.UpdateAsync(new EndPoint(new Uri(testUrl), HttpMethod.Put), JObject.FromObject(new object()), this.exceptionProcessor);

The PutAsync keep running without return exception. Here is the code.

Mock<RestClient> rc = new Mock<RestClient>();
rc.Setup(x => x.PutAsync(new Uri(testUrl), JObject.FromObject(new object()), new NameValueCollection()))
.Throws(new Exception("TestMessage"));

var result = await this.repository.UpdateAsync(new EndPoint(new Uri(testUrl), HttpMethod.Put), JObject.FromObject(new object()), this.exceptionProcessor);
Assert.IsTrue(result.ErrorMessages.GetValue(string.Empty).Equals("TestMessage"));

here is the main part of UpdateAsync, when process goes here, it will enter GetClient() first and then jump to Exception direct. This test was wrote using Shimes, but we don't want to use Shimes anymore, therefore I need to use another way to do.

public virtual async Task<GenericOperationResult<object>> UpdateAsync(EndPoint endpoint, JContainer obj, IExceptionProcessor exceptionProcessor, NameValueCollection headers){

     if (endpoint.ActionMethod == HttpMethod.Put)
     {
        result = await this.GetClient().PutAsync(endpoint.Url, obj, headers);
     }
     else if (endpoint.ActionMethod == HttpMethod.Post)
     {
        result = await this.GetClient().PostAsync(endpoint.Url, obj, headers);
     }
     else
     {
        throw new ConfigurationException("Update supports only POST or PUT verbs. Check endpoint configuration.");
     }
     return new GenericOperationResult<object>(200, result); 
}
Kun-Yao Wang
  • 192
  • 1
  • 3
  • 16
  • 1
    when the setup expectation does not match what is actually passed to the mocked method then it wont behave as expected when invoked. – Nkosi Feb 01 '19 at 16:12
  • You probably want `.Returns(Task.FromException(new Exception("TestMessage")))` instead of `Throws`. – Lee Feb 01 '19 at 16:16
  • @Lee with the way you offer, it shows can not convert Tasks.Task to Linq.JObject – Kun-Yao Wang Feb 03 '19 at 19:32

1 Answers1

2

You are instantiating new objects in your setup, which are different from the objects you are instantiating in your call to UpdateAsync, so they won't match and the Mock object won't throw the exception. You could instead setup the mock to throw the exception if objects of the correct types are passed in, with the Url param also checking it has the testUrl, for example:

rc.Setup(x => x.PutAsync(It.Is<Uri>(u => u.OriginalString == testUrl), It.IsAny<JObject>(), It.IsAny<NameValueCollection>())
    .ThrowsAsync(new Exception("TestMessage"));
Nkosi
  • 235,767
  • 35
  • 427
  • 472
PRS
  • 741
  • 1
  • 7
  • 27
  • Thanks for replay. With your way is more making sense. however the process still not does not exception when PutAsync is invoke, this is PutAsync , public virtual Task PutAsync(Uri uri, JContainer contentObject, NameValueCollection headers = null), should I change validation rule to make it be triggered? – Kun-Yao Wang Feb 03 '19 at 20:13
  • Ah you should be using ThrowsAsync rather than Throws (code updated), although you will probably need to sure your PutAsync method is actually marked as async. – PRS Feb 04 '19 at 11:30
  • the PutAsync is a virtual method, public virtual Task PutAsync(Uri uri, JContainer contentObject, NameValueCollection headers = null) – Kun-Yao Wang Feb 04 '19 at 11:49
  • Can you change the virtual method signature to be async? (it is possible: https://stackoverflow.com/questions/25015853/is-it-ok-to-have-virtual-async-method-on-base-class). Failing this perhaps you could provide all your code. It would be helpful to see the whole UpdateAsync method. – PRS Feb 04 '19 at 12:55
  • I updated my question, UpdateAsync is added , thanks for help – Kun-Yao Wang Feb 04 '19 at 13:05
  • Currently the custom exception is not working, I also create another testing project and test a very simple method by this same way, the custom exception is also not working. very strange.. – Kun-Yao Wang Feb 04 '19 at 13:07
  • I can't see any code that actually injects the mocked object rc into your repository class. You are setting up a mock object but I can't see how you are using it? – PRS Feb 04 '19 at 13:57
  • 1
    See the answer to this: https://codereview.stackexchange.com/questions/115928/unit-testing-with-dependency-injection-and-moq Note in the test method how the mock is passed into the object tested in it's constructor. – PRS Feb 04 '19 at 14:22
  • the main class I test is RestClient, it is without interface, is it still possible to mock? – Kun-Yao Wang Feb 04 '19 at 14:39