-->

Untitesting/Moq method calling webrequest

2019-07-29 11:01发布

问题:

I want to test a class that via a Webrequest sends texts, how can I using Moq mock the GetRequest methode, to test the GetRequest?

public class Sender

public void Send(string Message)
{
...
WebRequest myReq = GetRequest(sParmeter);
}

protected WebRequest GetRequest(string URl)
        {
            return WebRequest.Create(URl);
        }
}

回答1:

One of the approaches that I was gonna suggest is the same as the response by AD.Net, but if you do not wish to modify your existing structure and still test you could do something like below:

Modify your original class as follows:

public class Sender
{
    public void Send(string Message)
    {
    ...
        WebRequest myReq = GetRequest(sParmeter);
    }

    protected virtual WebRequest GetRequest(string URl)
    {
        return WebRequest.Create(URl);
    }
}

and in your test project extend this class as follows:

public class MockSender: Sender
{
    private WebRequest _response;
    public MockSender(WebRequest response)
    {
    _response=response;       //initialize data to be returned
    }
    protected override WebRequest GetRequest(string URl)
    {
        //return your test;
    }
}

and now in your test create an instance of type MockSender and call the Send method on it.

Moq expects your class to be abstract or you to implement an interface and thus mock the interface which is what AD.Net has described

Hope this helps..



回答2:

For something like this, the easy way would be to move your WebRequest instance and its action behind an interfaced intermediary.

Example:

public interface IWebRequestHandler
{
WebRequest GetRequest (string URI);
}

public class WebRequestHandler : IWebRequestHandler
{
public WebRequest GetRequest (string URI)
{
return WebRequest.Create(URl);
}
} 

Your sender class should have an injectable instance of IWebRequestHandler and you can mock it with MOQ, set up expctations, verify it gets called and anything else you might want.

public class Sender
{
public IWebRequestHandler Handler{get;set;}
public void Send(string Message)
{
Handler.GetRequest(new URI(Message));//call the method with right params, just an example
}
}


回答3:

Alternative is to pass the IWebRequestCreate method in to the constructor.

    public HTTPRequestFactory(IWebRequestCreate create)
    {
        _IWebRequestCreate = create;

    }

    public HTTPRequestFactory()
    {
        //Do nothing this is the real constructor, above is just for testing.
    }

    public WebRequest Create(String uri)
    {
        Uri _uri = new Uri("http://"+this.address+uri);
        request =  (HttpWebRequest)this.Create(_uri);
        return request;
    }

    public WebRequest  Create(Uri uri)
        if (null == _IWebRequestCreate)
        {
            //use the real one
            request = WebRequest.Create(uri);
        }
        else
        {
            //testing so use test one
            request = _IWebRequestCreate.Create(uri);
        }
        return request;
    }

} Then you can use a standard test to confirm it gets called like you want.

        [Test]
    public void NewwebrequestCreatesWebRequest()
    {
        var mockCreate = new Mock<IWebRequestCreate>();
        mockCreate.Setup(x => x.Create(It.IsAny<Uri>()));
        HTTPRequestFactory webrequest = new HTTPRequestFactory(mockCreate.Object);
        HttpWebRequest request = (HttpWebRequest)webrequest.Create(testURI);
        mockCreate.VerifyAll();       
    }

    [Test]
    public void webrequestUsesAddressProperty()
    {
        var mockCreate = new Mock<IWebRequestCreate>();
        string IP = "10.99.99.99";
        Uri expected = new Uri("http://10.99.99.99/services");
        mockCreate.Setup(x => x.Create(expected));
        HTTPRequestFactory webrequest = new HTTPRequestFactory(mockCreate.Object);
        webrequest.address = IP;
        HttpWebRequest request = (HttpWebRequest)webrequest.Create(testURI);
        mockCreate.VerifyAll();
    }

The reason for two Create functions is that you want to pass in a string Create(string) and IWebRequestCreate requires a Create(Uri).

Edited because standard dependancy injection does not work with IWebRequestCreate. Standard pattern is Instantiate an object with the Interface and pass it in through the constructor. Since WebRequest cannot be created with a constructor and interfaces canot be instantiated, the above logic works around that.



标签: c# moq