Build A Contract 建立约定
First, we'll define an interface and a corresponding implementation:
首先我们定义一个接口,然后实现该接口。
interface UserRepositoryInterface
{
public function all();
}
class DbUserRepository implements UserRepositoryInterface
{
public function all()
{
return User::all()->toArray();
}
}
Next, we'll inject an implementation of this interface into our controller:
然后我们将该接口的实现注入我们的控制器。
class UserController extends BaseController
{
public function __construct(UserRepositoryInterface $users)
{
$this->users = $users;
}
public function getIndex()
{
$users=$this->users->all();
return View::make('users.index', compact('users'));
}
}
Now our controller is completely ignorant of where our user data is being stored. In this case, ignorance is bless! Our data could be coming from MySQL, MongoDB, or Redis. Our controller doesn't know the difference, nor should it care. Just by making this small change, we can test our web layer independent of our data layer, as well as easily switch our storage implementation.
现在我们的控制器就完全和数据层面无关了。在这里无知是福!我们的数据可能来自 MySQL,MongoDB 或者 Redis。我们的控制器不知道也不需要知道他们的区别。仅仅做出了这么小小的改变,我们就可以独立于数据层来测试 Web 层了,将来切换存储实现也会很容易。
Respect Boundaries 严守边界
Remember to respect responsibility boundaries. Controllers and routes serve as a mediator between HTTP and your application. When writing large applications, don't clutter them up with your domain logic.
记得要保持清晰的责任边界。 控制器和路由是作为 HTTP 和你的应用程序之间的中间件来用的。当编写大型应用程序时,不要将你的领域逻辑混杂在其中(控制器、路由)。
To solidify our understanding, let's write a quick test. First, we'll mock the repository and bind it to the application IoC container. Then, we'll ensure that the controller properly calls the repository:
为了巩固学到的知识,咱们来写一个测试案例。首先,我们要模拟一个资料库然后绑定到应用的 IoC 容器里。 然后,我们要保证控制器正确的调用了这个资料库:
public function testIndexActionBindsUsersFromRepository()
{
// Arrange...
$repository = Mockery::mock('UserRepositoryInterface');
$repository->shouldReceive('all')->once()->andReturn(array('foo'));
App::instance('UserRepositoryInterface', $repository);
// Act...
$response = $this->action('GET', 'UserController@getIndex');
// Assert...
$this->assertResponseOk();
$this->assertViewHas('users', array('foo'));
}
Are you Mocking Me 你在模仿我么?
In this example, we used the
Mockery
mocking library. This library provides a clean, expressive interface for mocking your classes. Mockery can be easily insalled via Composer.在上面的例子里, 我们使用了名为
Mockery
的模仿库。 这个库提供了一套整洁且富有表达力的方法,用来模仿你写的类。 Mockery 可以通过 Composer 安装。