用于集成测试的存根网络服务器

发布于 2024-09-06 00:13:36 字数 304 浏览 4 评论 0原文

我有一些集成测试,我想验证针对第三方网络服务器的某些要求。我想用一个存根服务器替换第三方服务器,该存根服务器只记录对其进行的调用。调用不需要成功,但我确实需要所发出请求的记录(主要是路径+查询字符串)。

我正在考虑仅使用 IIS 来实现此目的。我可以 1) 设置一个空站点,2) 修改系统的主机文件以将请求重定向到该站点 3) 在每次测试结束时解析日志文件。

这是有问题的,因为对于 IIS,日志文件不会立即写入,而是会连续写入。我需要找到该文件,在测试前读取内容,在测试后等待一段不确定的时间,读取更新内容等。

有人可以想出一种更简单的方法吗?

I have some integration tests where I want to verify certain requires are made against a third-[arty webserver. I was thinking I would replace the third-party server with a stub server that simply logs calls made to it. The calls do not need to succeed, but I do need a record of the requests made (mainly just the path+querystring).

I was considering just using IIS for this. I could 1) set up an empty site, 2) modify the system's host file to redirect requests to that site 3) parse the log file at the end of each test.

This is problematic as for IIS the log files are not written to immediately, and the files are written to continuosly. I'll need to locate the file, read the contents before the test, wait a nondeterministic amount of time after the test, read the update contents, etc.

Can someone think of a simpler way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

残龙傲雪 2024-09-13 00:13:36

您可以使用 System.Net.HttpListener ( MSDN 链接)。

它作为嵌入式 Web 服务器工作,这意味着您甚至可以即时检查访问,而无需解析日志文件。

我最近在代码中使用的一个类:

class Listener
{
    private HttpListener listener = null;

    public event EventHandler CommandReceived;

    public Listener()
    {
        this.listener = new HttpListener();
        this.listener.Prefixes.Add("http://localhost:12345/");
    }

    public void ContextReceived(IAsyncResult result)
    {
        if (!this.listener.IsListening)
        {
            return;
        }
        HttpListenerContext context = this.listener.EndGetContext(result);
        this.listener.BeginGetContext(this.ContextReceived, this.listener);

        if (context != null)
        {
            EventHandler handler = this.CommandReceived;
            handler(context, new EventArgs());
        }
    }

    public void Start()
    {
        this.listener.Start();
        this.listener.BeginGetContext(this.ContextReceived, this.listener);
    }

    public void Stop()
    {
        this.listener.Stop();
    }
}

You could use the System.Net.HttpListener ( MSDN LINK ).

It works as embedded WebServer, this means you can even check the access on-the-fly without having to parse log files.

A class i used in my Code recently:

class Listener
{
    private HttpListener listener = null;

    public event EventHandler CommandReceived;

    public Listener()
    {
        this.listener = new HttpListener();
        this.listener.Prefixes.Add("http://localhost:12345/");
    }

    public void ContextReceived(IAsyncResult result)
    {
        if (!this.listener.IsListening)
        {
            return;
        }
        HttpListenerContext context = this.listener.EndGetContext(result);
        this.listener.BeginGetContext(this.ContextReceived, this.listener);

        if (context != null)
        {
            EventHandler handler = this.CommandReceived;
            handler(context, new EventArgs());
        }
    }

    public void Start()
    {
        this.listener.Start();
        this.listener.BeginGetContext(this.ContextReceived, this.listener);
    }

    public void Stop()
    {
        this.listener.Stop();
    }
}
成熟的代价 2024-09-13 00:13:36

我正在寻找上面发布的同一问题的解决方案。我有一个连接到外部服务器的传出 http 请求,我想验证输出 (XML)。

我正在使用 NUnit 进行测试。我在创建一个能够接收输出同时调用输出逻辑的测试时遇到了麻烦。我尝试的所有内容都会挂在发送或接收部分。

感谢我在这篇文章中找到的答案,我能够创建一个对我有用的测试,并且我想分享它,以防它对其他人有用。

夹具:

[NonParallelizable]
public abstract class ListenerFixture : MyNormalFixture
{
    protected readonly string ListenerUrl = $"http://{IPAddress.Loopback}:1234/";
    protected IAsyncResult CallbackContext = null!;
    protected XDocument CallbackResult = new();
    private readonly HttpListener _listener;

    protected ListenerFixture()
    {
        _listener = new HttpListener();
        _listener.Prefixes.Add(ListenerUrl);
    }

    [SetUp]
    public override async Task SetUp()
    {
        await base.SetUp();
        
        _listener.Start();
        
        CallbackContext = _listener.BeginGetContext(ListenerCallback, _listener);
    }

    [TearDown]
    public override async Task TearDown()
    {
        _listener.Stop();

        await base.TearDown();
    }

    [OneTimeTearDown]
    public void OneTimeTearDown()
    {
        _listener.Close();
    }
    
    private void ListenerCallback(IAsyncResult result)
    {
        if (!_listener.IsListening)
        {
            return;
        }
    
        var context = _listener.EndGetContext(result);
        
        var resultString = new StreamReader(context.Request.InputStream).ReadToEnd();
        CallbackResult = XDocument.Parse(resultString);
        
        context.Response.Close();
    }
}

测试:

internal class SendXmlShould : ListenerFixture
{
    [Test, Timeout(10000)]
    public async Task SendXml()
    {
        // Arrange
        var expected = XDocument.Load("TestData/test-output.xml");
        
        /* Some setup for the output logic */
        
        // Act
        await /*Invoke the output logic*/;
        CallbackContext.AsyncWaitHandle.WaitOne();

        // Assert
        CallbackResult.Should().BeEquivalentTo(expected);
    }
}

I was looking for a solution to the same problem posted above. I have an outgoing http request that connects to an external server, and I wanted to verify the output (XML).

I am using NUnit for my tests. I was having trouble creating a test that is able to receive the output, while at the same time invoking the output logic. Everything I tried would either hang at the sending or receiving part.

Thanks to the answers I found in this post I was able to create a test that worked for me, and I wanted to share it in case it could be useful to someone else.

Fixture:

[NonParallelizable]
public abstract class ListenerFixture : MyNormalFixture
{
    protected readonly string ListenerUrl = 
quot;http://{IPAddress.Loopback}:1234/";
    protected IAsyncResult CallbackContext = null!;
    protected XDocument CallbackResult = new();
    private readonly HttpListener _listener;

    protected ListenerFixture()
    {
        _listener = new HttpListener();
        _listener.Prefixes.Add(ListenerUrl);
    }

    [SetUp]
    public override async Task SetUp()
    {
        await base.SetUp();
        
        _listener.Start();
        
        CallbackContext = _listener.BeginGetContext(ListenerCallback, _listener);
    }

    [TearDown]
    public override async Task TearDown()
    {
        _listener.Stop();

        await base.TearDown();
    }

    [OneTimeTearDown]
    public void OneTimeTearDown()
    {
        _listener.Close();
    }
    
    private void ListenerCallback(IAsyncResult result)
    {
        if (!_listener.IsListening)
        {
            return;
        }
    
        var context = _listener.EndGetContext(result);
        
        var resultString = new StreamReader(context.Request.InputStream).ReadToEnd();
        CallbackResult = XDocument.Parse(resultString);
        
        context.Response.Close();
    }
}

The test:

internal class SendXmlShould : ListenerFixture
{
    [Test, Timeout(10000)]
    public async Task SendXml()
    {
        // Arrange
        var expected = XDocument.Load("TestData/test-output.xml");
        
        /* Some setup for the output logic */
        
        // Act
        await /*Invoke the output logic*/;
        CallbackContext.AsyncWaitHandle.WaitOne();

        // Assert
        CallbackResult.Should().BeEquivalentTo(expected);
    }
}
长梦不多时 2024-09-13 00:13:36

是的,我认为你不需要一个完整的网络服务器。您不需要测试 HTTP。

需要测试的是您发送和接收的底层数据结构。因此,只需为此创建测试(即,您可以使用预期的内容以及您打算接收的内容等来验证生成的数据格式)。

测试数据,而不是协议(显然,除非协议是自定义的)。

Yeah, I don't think you need a whole webserver. You don't need to test HTTP.

What you do need to test is the underlying data structure that you're sending and receiving. So just create tests for that (i.e. make a point at which you can validate your generate dataformat with what is expected, and also with what you intend to receive, etc).

Test the data, not the protocol (unless, obviously, the protocol is custom).

瑾夏年华 2024-09-13 00:13:36

我在许多项目中做过类似的事情。

您不想创建存根 Web 服务。这只是添加了您不需要的依赖项。我所做的是创建一个模仿 Web 服务 API 的界面。然后我创建了一个代理类,它将调用实时系统中的 Web 服务。为了进行测试,我使用 RhinoMocks 创建模拟类,该类返回我想要测试的结果。这对我来说非常有用,因为我可以产生各种“意外”行为,而这些行为在实时系统中是不可能的。

public interface IServiceFacade {
    string Assignments();
}

public class ServiceFacade : IServiceFacade {
    private readonly Service _service;

    public ServiceFacade(Service service) {
        _service = service;
    }

    public string Assignments() {
        return _service.Assignments();
    }
}

然后我的测试代码包含这样的内容:

        var serviceFacade = MockRepository.GenerateMock<IServiceFacade>();
        serviceFacade.Stub(sf => sf.Assignments()).Return("BLAH BLAH BLAH");

或者

        serviceFacade.Stub(sf => sf.Assignments()).Return(null);

或者

        serviceFacade.Stub(sf => sf.Assignments()).Throw(new Exception("Some exception"));

我发现这非常有用。

I've done something very similar to this in a number of projects.

You don't want to create stubbed web service. That's just adding a dependency you don't need. What I did was create an interface which mimics the web service's API. I then created a proxy class that will call the web service in the live system. For testing I used RhinoMocks to create mocked classes that return the results I wanted to test for. This was very useful for me, as I could then produce all sorts of 'unexpected' behaviour which wouldn't be possible with the live system.

public interface IServiceFacade {
    string Assignments();
}

public class ServiceFacade : IServiceFacade {
    private readonly Service _service;

    public ServiceFacade(Service service) {
        _service = service;
    }

    public string Assignments() {
        return _service.Assignments();
    }
}

Then my test code contained stuff like this:

        var serviceFacade = MockRepository.GenerateMock<IServiceFacade>();
        serviceFacade.Stub(sf => sf.Assignments()).Return("BLAH BLAH BLAH");

or

        serviceFacade.Stub(sf => sf.Assignments()).Return(null);

or

        serviceFacade.Stub(sf => sf.Assignments()).Throw(new Exception("Some exception"));

I found this very useful.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文