我一直在阅读有关测试的文章,我发现一些文章说我应该有更多的单元测试而不是功能测试;一个叫做测试金字塔的东西。
我已经使用TDD启动了一个简单的系统,到目前为止,我基本上已经编写了特性测试(下面的例子),因为我知道它们是最重要的,因为它们与用户真正的行为(比如发出帖子请求)更相关(点击一个按钮,这样做),并收到一个回应。但因为我读到的,我现在不确定是应该继续这样做,还是应该创建单元测试来测试我在控制器中调用的服务方法。
即使为我的每个服务方法编写了单元测试,我仍然会有比单元测试更多或相等的功能测试,因为我的服务的每个方法都与一个端点相关,用户可以向它发送不同的数据。
另外,如果我理解测试错误,请随时纠正我.谢谢
测试项目:
<?php
namespace Tests\Feature\Cms;
use App\Models\Group;
use App\Models\Modules;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
class UsersTest extends TestCase
{
use WithFaker, RefreshDatabase;
/** @test */
public function unauthenticated_users_are_redirected()
{
$this->withoutExceptionHandling();
$response = $this->get(route('cms.users.index'));
$response->assertRedirect();
}
/** @test */
public function a_user_can_be_created()
{
$this->withoutExceptionHandling()->signIn();
$password = $this->faker->password(6, 12);
$user_data = [
'email' => $this->faker->safeEmail(),
'fk_group_id' => Group::factory()->has(Modules::factory(), 'modules')->create()->id,
'name' => $this->faker->name(),
'password' => $password,
'password_confirmation' => $password,
];
$response = $this->post(route('cms.users.store'), $user_data);
$response->assertSessionHas('response', cms_response(trans('cms.users.success_create')));
}
/** @test */
public function if_passwords_dont_match_when_creating_a_user_an_error_is_returned()
{
$this->signIn();
$user_data = [
'email' => $this->faker->safeEmail(),
'fk_group_id' => Group::factory()->has(Modules::factory(), 'modules')->create()->id,
'name' => $this->faker->name(),
'password' => $this->faker->password(6, 12),
'password_confirmation' => $this->faker->password(6, 12),
];
$response = $this->post(route('cms.users.store'), $user_data);
$this->checkIfSessionErrorMatchesString('password', 'A senha e confirmação de senha não são iguais.');
$this->checkIfSessionErrorMatchesString('password_confirmation', 'A senha e confirmação de senha não são iguais.');
}
/** @test */
public function a_user_can_be_updated()
{
$this->withoutExceptionHandling()->signIn();
$user = User::factory()->withPassword($this->faker->password(6, 12))->create();
$password = $this->faker->password(6, 12);
$user_data = [
'email' => $this->faker->safeEmail(),
'fk_group_id' => Group::factory()->has(Modules::factory(), 'modules')->create()->id,
'name' => $this->faker->name(),
'password' => $password,
'password_confirmation' => $password,
];
$response = $this->patch(route('cms.users.update', ['user' => $user->id]), $user_data);
$response->assertSessionHas('response', cms_response(trans('cms.users.success_update')));
}
/** @test */
public function if_the_user_isnt_found_an_error_is_returned()
{
$this->withoutExceptionHandling()->signIn();
$user = User::all()->last();
$password = $this->faker->password(6, 12);
$user_data = [
'email' => $this->faker->safeEmail(),
'fk_group_id' => Group::factory()->has(Modules::factory(), 'modules')->create()->id,
'name' => $this->faker->name(),
'password' => $password,
'password_confirmation' => $password,
];
$response = $this->patch(route('cms.users.update', ['user' => $user->id + 1]), $user_data);
$response->assertSessionHas('response', cms_response(trans('cms.users.error_user_not_found'), false, 400));
}
/** @test */
public function a_user_can_be_updated_without_updating_its_password()
{
$this->withoutExceptionHandling()->signIn();
$user = User::factory()->withPassword($this->faker->password(6, 12))->create();
$user_data = [
'email' => $this->faker->safeEmail(),
'fk_group_id' => Group::factory()->has(Modules::factory(), 'modules')->create()->id,
'name' => $this->faker->name(),
];
$response = $this->patch(route('cms.users.update', ['user' => $user->id]), $user_data);
$response->assertSessionHas('response', cms_response(trans('cms.users.success_update')));
}
/** @test */
public function if_passwords_dont_match_when_updating_a_user_an_error_is_returned()
{
$this->signIn();
$user = User::factory()->withPassword($this->faker->password(6, 12))->create();
$user_data = [
'email' => $this->faker->safeEmail(),
'fk_group_id' => Group::factory()->has(Modules::factory(), 'modules')->create()->id,
'name' => $this->faker->name(),
'password' => $this->faker->password(6, 12),
'password_confirmation' => $this->faker->password(6, 12),
];
$this->patch(route('cms.users.update', ['user' => $user->id]), $user_data);
$this->checkIfSessionErrorMatchesString('password', 'A senha e confirmação de senha não são iguais.');
$this->checkIfSessionErrorMatchesString('password_confirmation', 'A senha e confirmação de senha não são iguais.');
}
/** @test */
public function users_can_be_excluded()
{
$this->withoutExceptionHandling()->signIn();
$users_id = User::factory(2)->withPassword($this->faker->password(6, 12))->create()->pluck('id');
$response = $this->delete(route('cms.users.destroy', $users_id));
$response->assertSessionHas('response', cms_response(trans('cms.users.success_delete')));
}
}
控制器:
<?php
namespace App\Http\Controllers\Cms;
use App\Http\Controllers\Controller;
use App\Http\Requests\UserRequest;
use App\Services\CmsUsersService;
use Illuminate\Http\Request;
class UsersController extends Controller
{
private $service;
public function __construct(CmsUsersService $service)
{
$this->service = $service;
}
public function store(UserRequest $request)
{
$result = $this->service->create($request->all());
return redirect()->back()->with('response', $result);
}
public function update(UserRequest $request, $id)
{
$result = $this->service->update($id, $request->all());
return redirect()->back()->with('response', $result);
}
public function destroy($users_id)
{
$result = $this->service->delete($users_id);
return redirect()->back()->with('response', $result);
}
}
服务项目:
<?php
namespace App\Services;
use App\Models\User;
use Exception;
use Illuminate\Support\Facades\Hash;
use App\Interfaces\CRUD;
class CmsUsersService implements CRUD
{
public function create(array $data)
{
$data['token'] = Hash::make($data['email']);
$data['password'] = Hash::make($data['password']);
User::create($data);
return cms_response(trans('cms.users.success_create'));
}
public function update(int $id, array $data)
{
try {
if (array_key_exists('password', $data)) {
$data['password'] = Hash::make($data['password']);
}
$user = $this->__findOrFail($id);
$user->update($data);
return cms_response(trans('cms.users.success_update'));
} catch (\Throwable $th) {
return cms_response($th->getMessage(), false, 400);
}
}
public function delete(string $ids)
{
User::whereIn('id', json_decode($ids))->delete();
return cms_response(trans('cms.users.success_delete'));
}
private function __findOrFail(int $id)
{
$user = User::find($id);
if ($user instanceof User) {
return $user;
}
throw new Exception(trans('cms.users.error_user_not_found'));
}
}
1条答案
按热度按时间k4ymrczo1#
我从实践和Jeffrey Way中学到,你主要做的是特性测试,而不是特别担心单元测试。直到那时,当你不确定底层的类方法不会像预期的那样工作时;您可以深入到单元级别并确保该方法也能处理边缘情况。