pytest-dev/pytest-asyncio

How to specify two different ports by `unused_tcp_port` fixture

asvetlov opened this issue ยท 12 comments

I have functional tests for my system which requires several components running on different ports
As I see unused_tcp_port has functional scope, so it's impossible to acquire two different ports (for different purposes, sure) in the same test.
Or maybe I missed something?

Nope, that's the current limitation. I'm not aware for any smaller scope than function, so I suppose we have two options here:

  • create a free port factory fixture (but then it's not as nice to use)
  • create more fixtures, unused_tcp_port_{1, 2, 3...}

Any ideas?

I think creating a port factory fixture is a nice approach, while keeping unused_tcp_port around to support the common case of needing a single port.

@asvetlov, a quick workaround you can use meanwhile is to create two intermediate fixtures:

@pytest.fixture
def port1(unused_tcp_port):
    return unused_tcp_port

@pytest.fixture
def port2(unused_tcp_port):
    return unused_tcp_port

def test_foo(port1, port2):
   ...

@nicoddemus please describe what do you mean under factory fixture?
Sorry, I'm a newbie in pytest.

Isn't your workaroud return the same value for port1 and port2?

please describe what do you mean under factory fixture?

Oh it's not a pytest term, I just meant a factory in the general sense. Something like this would work nicely IMO:

def test_foo(unused_port_factory):
    port1 = unused_port_factory.get_port()
    port2 = unused_port_factory.get_port()

Isn't your workaroud return the same value for port1 and port2?

Argh, of course it is, my bad. Please disregard this. ๐Ÿ˜…

Is unused_port_factory a fixture? Can fixture have a methods?
If it's not a fixture should I import the name?

The idea would be to create it as a fixture, yeah. Fixtures can be any object you like, so yes, they can have methods :)

The idea would be to create it as a fixture, yeah.

Yes, sorry for not being more clear. ๐Ÿ˜„

I'll get this done over the weekend. Beside get_port (I think I prefer next_port instead, so it's clearer it can be called n times and is not idempotent), a method for generating several ports at once might be useful. Like this:

p1, p2, p3 = unused_port_factory.next_ports(3)

I think I prefer next_port instead

๐Ÿ‘

a method for generating several ports at once might be useful

Also ๐Ÿ‘

Sounds perfect!

I've just pushed out 0.2.0 to PyPI, which includes the unused_tcp_port_factory fixture. The end result is slightly simpler than what we discussed here (see the README), but it should suffice for this use case.

I believe you even don't need produced set -- bound port will be inaccessible for reusing for a while unless SO_REUSEADDR specified.