public function method($path, $closure = null)
    {
        if ($this->_needToBePatched) {
            $layer = Double::classname();
            Monkey::patch($this->_reference, $layer);
            $this->_needToBePatched = false;
            $this->_reference = $layer;
        }

        $reference = $this->_reference;

        if (!$path) {
            throw new InvalidArgumentException("Method name can't be empty.");
        }

        $names = is_array($path) ? $path : [$path];

        $this->_chain = [];
        $total = count($names);

        foreach ($names as $index => $name) {
            if (preg_match('/^::.*/', $name)) {
                $reference = is_object($reference) ? get_class($reference) : $reference;
            }

            $hash = Suite::hash($reference);
            if (!isset(static::$_registered[$hash])) {
                static::$_registered[$hash] = new static($reference);
            }

            $instance = static::$_registered[$hash];
            if (is_object($reference)) {
                Suite::register(get_class($reference));
            } else {
                Suite::register($reference);
            }
            if (!isset($instance->_methods[$name])) {
                $instance->_methods[$name] = [];
                $instance->_stubs[$name] = Double::instance();
            }

            $method = new Method([
                'parent'    => $this,
                'reference' => $reference,
                'name'      => $name
            ]);
            $this->_chain[$name] = $method;
            array_unshift($instance->_methods[$name], $method);

            if ($index < $total - 1) {
                $reference = $instance->_stubs[$name];
                $method->andReturn($instance->_stubs[$name]);
            }
        }

        $method = end($this->_chain);
        if ($closure) {
            $method->andRun($closure);
        }
        return $method;
    }