C# 如何模拟 Web 服务

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1615093/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 19:24:19  来源:igfitidea点击:

How to mock a web service

c#.netweb-servicesmoqmocking

提问by zachary

Do I have to rewrite my code to do this into an interface? Or is there an easier way? I am using Moq

我是否必须重写我的代码才能在接口中执行此操作?或者有更简单的方法吗?我正在使用最小起订量

采纳答案by Joseph

What I usually do is build a wrapper or an adapter around my web service and just mock that.

我通常做的是围绕我的 Web 服务构建一个包装器或适配器,然后模拟它。

for instance:

例如:

public class ServiceAdapter: IServiceAdapter
{
    public void CallSomeWebMethod()
    {
        var someService = new MyWebService();
        someService.SomeWebMethod();
    }
}

Then I just stub the service adapter.

然后我只是存根服务适配器。

[Test]    
public void SomeMethod_Scenario_ExpectedResult()
{
    var adapterMock = new Mock<IServiceAdapter>();
    //do your test
}

回答by Jon Skeet

I blogged about thisa long time ago. Basically using partial classes and a bit of effort (either automated or manual, depending on how often you're going to change the web service) you can make the web service proxy class implement an interface. You can then mock it as normal.

很久以前我在博客上写过这个。基本上使用部分类和一些努力(自动或手动,取决于您要更改 Web 服务的频率),您可以使 Web 服务代理类实现一个接口。然后你可以像往常一样模拟它。

回答by johnny g

been writing a couple of responses about unit testing and mocking lately. I wrote elsewhere that it's important to ask yourself what exactlyare you testing. Regarding your particular situation, I would hope the answer is "I am testing the business logic my WebService is exposing", and not"I am testing my WebService" - there's a difference.

最近写了一些关于单元测试和模拟的回复。我在别处写道,问问自己到底在测试什么很重要。关于您的特定情况,我希望答案是“我正在测试我的 WebService 公开的业务逻辑”,而不是“我正在测试我的 WebService” - 有区别。



If your concerns are server-side

如果您担心的是服务器端

You do not need to test WebServices in general. MS has already done that. Millions of people have done that. Testing the transport layer, the protocol, the definition of WebServices is a waste of time.

一般不需要测试 WebServices。MS已经做到了。数百万人已经这样做了。测试传输层、协议、WebServices 的定义是浪费时间。

You need to target your business logic. The best way to do this is to separateyour business logic from your WebService. Consider the following

您需要针对您的业务逻辑。最好的方法是您的业​​务逻辑与您的 WebService分开。考虑以下

public class MyWebSevice : System.Web.Services.WebService
{
    private AuthenticationService _auth = new AuthenticationService ();
    private int _count = 0;
    [WebMethod]
    public string DoSomething ()
    {
        // embedded business logic, bad bad bad
        if (_auth.Authenticate ())
        {
            _count++;
        }
        return count.ToString ();
    }
}

there is no way to test that logic without invoking the WebService directly. What you really want is

如果不直接调用 WebService,就无法测试该逻辑。你真正想要的是

public class MyService 
{
    // keeners will realise this too should be injected
    // as a dependency, but just cut and pasted to demonstrate
    // isolation
    private AuthenticationService _auth = new AuthenticationService ();
    private int _count = 0;
    public string DoSomething ()
    {
        if (_auth.Authenticate ())
        {
            _count++;
        }
        return count.ToString ();
    }
}

in prod

生产中

// this web service is now a consumer of a business class,
// no embedded logic, so does not require direct testing
public class MyWebSevice : System.Web.Services.WebService
{
    private readonly MyService _service = new MyService ();

    [WebMethod]
    public string DoSomething ()
    {
        _service.DoSomething ();
    }
}

in test

测试中

// test business logic without web service! yay!
[Test]
public void Test_DoSomething ()
{
    MyService service = new MyService ();
    string actual = service.DoSomething ();
    // verify results
}

managing dependencies [like the AuthenticationService member] is a separate issue. However, making your WebMethods simple passthroughsto proper underlying business classes and removing logic from them completely, allows you to target "real" user code as opposed to the plumbing of your typical WebService implementation.

管理依赖项 [如 AuthenticationService 成员] 是一个单独的问题。然而,使您的 WebMethods简单地传递到正确的底层业务类并完全从它们中删除逻辑,允许您定位“真实”用户代码,而不是典型的 WebService 实现的管道。



If your concerns are client-side

如果您的问题是客户端

You have a business component callinga webservice, and I agree that you don't want to create a client for unit testing.

您有一个调用Web 服务的业务组件,我同意您不想为单元测试创​​建客户端。

public partial class MyWebService :
    System.Web.Services.Protocols.SoapHttpClientProtocol 
{
    ...
    public string DoSomething () { ... }
}

public class MyClient
{
    public void CallService ()
    {
        MyWebService client = new MyWebService ();
        client.DoSomething ();
    }
}

Here, you have dependency issues, namely you cannot test MyClient.CallService without instantiating and hosting your WebService. Especially disconcerting if you do not own or host said remote service. In this case, yes, you should write against an interface - once again to separate and isolate business logic.

在这里,您有依赖性问题,即您无法在不实例化和托管您的 WebService 的情况下测试 MyClient.CallService。如果您不拥有或托管所述远程服务,则尤其令人不安。在这种情况下,是的,您应该针对接口编写 - 再次分离和隔离业务逻辑。

public interface IMyWebService
{
    string DoSomething ();
}

public class MyWebServiceWrapper : IMyWebService
{
    public string DoSomething () 
    {
        MyWebService client = new MyWebService ();
        client.DoSomething ();
    }
}

public class MyClient
{
    private readonly IMyWebService _client = null;
    public MyClient () : this (new MyWebServiceWrapper ()) { }
    public MyClient (IMyWebService client)
    {
        _client = client;
    }
    public void CallService ()
    {
        _client.DoSomething ();
    }
}

in test

测试中

[Test]
public void Test_CallService ()
{
    IMyWebService mockService = null;
    // instantiate mock with expectations
    MyClient client = new MyClient (mockService);
    client.CallService ();
    // verify results
}


In general, if a class's dependencies are in-proc services, the decision to apply a pattern like Dependency Injection [DI] or Inversion of Control [IoC] is up to you - and your desire to isolate and unit test these services will inform your design. However, if a class's dependencies cross a process boundary, eg Database or WebService, I highly recommend applying these patterns as we did above.

通常,如果类的依赖项是进程内服务,应用依赖注入 [DI] 或控制反转 [IoC] 之类的模式的决定取决于您 - 您希望隔离和单元测试这些服务将通知您设计。但是,如果类的依赖关系跨越进程边界,例如数据库或 Web 服务,我强烈建议像我们上面所做的那样应用这些模式。

Really, it's just plain old interface development. You probably already see how it pays off.

真的,这只是普通的旧界面开发。您可能已经看到它是如何获得回报的。

:)

:)

回答by SalmanAA

there is an easy way. for example if we have WebService class with the name DbService, first create an interface for it (ex. IService), and use this interface for mocking, then add a class to your project and put this:

有一个简单的方法。例如,如果我们有名为 DbService 的 WebService 类,首先为其创建一个接口(例如 IService),并使用此接口进行模拟,然后将一个类添加到您的项目中并放置:

public partial class DbService:IService {

}

leave class empty, because of web services are partial class we use this implementation. (previously

将类留空,因为 Web 服务是部分类,我们使用此实现。(之前