1

If you have a class that responds differently depending upon constructor arguments, how do you go about writing a spec for that class?

class Route
{
  function __construct($url, array $methods = array())
  {
    // stores methods and url in private member variables
    // creates a regex to match $url against incoming request URLs
  }

  public function isMatch($url)
  {
    // checks if the incoming request url matches against this url
  }
}

Example use:

$a = new Route('/users/:id');
$a->isMatch('/users/1') // returns true;
$b = new Route('/users');
$b->isMatch('/users') // returns true

If I set up my spec for this class using the let function from phpspec:

class Route extends ObjectBehaviour
{
  function let() 
  {
    $this->beConstructedWith('/users/:id')
  }
}

My spec can only check if the behaviour of this class works in one of the cases.

I've contemplated adding setter methods to allow me to test around this, but it seems like I'd be breaking encapsulation for the purpose of testing.

I'm struggling to find anything that touches upon this, so I'm started to think that maybe this is bad code smell situation.

4

2 回答 2

3

beConstructedWith()并不总是需要从let()方法中调用。您也可以从规范中调用它。

在我看来,以不止一种方式设置对象并没有错。但是,您应该避免在构造函数中做太多工作

于 2013-05-20T16:09:13.200 回答
1
  1. 构造函数只能用于获取将在此处设置为成员属性的变量。这里不应该做进一步的逻辑......
  2. 按照第 1 点的想法,应该有另一个逻辑来确定接下来会发生什么(例如if Object->hasProperty(X) then do x(),等)
  3. 那么评论将是简单明了的。

例子:

class Route
{
    private $url;
    private $methods = array();

    /**
     * Constructor method, sets the attributes to private member variables
     * @param string $url URL pattern
     * @param array $methods Methods that should be used with given URL
     */
    function __construct($url, $methods = array())
    {
        $this->url      = $url;
        $this->methods  = $methods;
    }

    // ...

}
于 2013-04-24T13:35:24.600 回答