-
Notifications
You must be signed in to change notification settings - Fork 59
[SangCT] Do homework #26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
7a6b87c
2accd82
0b2139a
17d41da
98bb649
3e838a2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| <?php | ||
|
|
||
| namespace Modules\Exercise03\Tests\Unit\Controllers; | ||
|
|
||
| use Illuminate\Http\JsonResponse; | ||
| use Modules\Exercise03\Http\Controllers\ProductController; | ||
| use Modules\Exercise03\Http\Requests\CheckoutRequest; | ||
| use Modules\Exercise03\Services\ProductService; | ||
| use Tests\TestCase; | ||
|
|
||
| class ProductControllerTest extends TestCase | ||
| { | ||
| /** | ||
| * @var \Mockery\MockInterface | ||
| */ | ||
| protected $productServiceMock; | ||
|
|
||
| protected function setUp(): void | ||
| { | ||
| parent::setUp(); | ||
|
|
||
| // Laravel helper: mock and bind to service container | ||
| $this->productServiceMock = $this->mock(ProductService::class); | ||
| } | ||
|
|
||
| /** | ||
| * A basic unit test example. | ||
| * | ||
| * @return void | ||
| */ | ||
| public function test__contruct() | ||
| { | ||
| $controller = new ProductController($this->productServiceMock); | ||
|
|
||
| $this->assertInstanceOf(ProductController::class, $controller); | ||
|
|
||
| } | ||
|
|
||
| public function test_index() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Test index là test cái gì, tên test case nên thể hiện được mục đích của test case Mục 1 trong checklist:
|
||
| { | ||
| $this->productServiceMock->shouldReceive('getAllProducts') | ||
| ->once() | ||
| ->andReturn([]); | ||
| $url = action([ProductController::class, 'index']); | ||
|
|
||
| $response = $this->get($url); | ||
|
|
||
| $response->assertViewIs('exercise03::index'); | ||
| $response->assertViewHas('products'); | ||
| } | ||
|
|
||
| public function test_checkout() | ||
| { | ||
| $input = [ | ||
| 1 => 2, | ||
| 2 => 3, | ||
| 3 => 3, | ||
| ]; | ||
|
|
||
| $request = $this->mock(CheckoutRequest::class); | ||
| $request->shouldReceive('input') | ||
| ->once() | ||
| ->with('total_products') | ||
| ->andReturn($input); | ||
|
|
||
| $this->productServiceMock->shouldReceive('calculateDiscount') | ||
| ->with($input) | ||
| ->once() | ||
| ->andReturn(7); | ||
|
|
||
| $controller = new ProductController($this->productServiceMock); | ||
|
|
||
| $this->assertInstanceOf(JsonResponse::class, $controller->checkout($request)); | ||
|
Comment on lines
+60
to
+73
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cái này viết theo cách dùng HTTP tests như ở There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Đoạn này nên có thêm assert cho |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| <?php | ||
|
|
||
| namespace Modules\Exercise03\Tests\Unit\Requests; | ||
|
|
||
| use Illuminate\Support\Arr; | ||
| use Illuminate\Support\Facades\Validator; | ||
| use Modules\Exercise03\Http\Requests\CheckoutRequest; | ||
| use Tests\TestCase; | ||
|
|
||
| class CheckoutRequestTest extends TestCase | ||
| { | ||
| public function test_rules() | ||
| { | ||
| $request = new CheckoutRequest(); | ||
|
|
||
| $this->assertSame([ | ||
| 'total_products' => 'required|array', | ||
| 'total_products.*' => 'nullable|integer|min:0', | ||
| ], $request->rules()); | ||
| } | ||
|
Comment on lines
+12
to
+20
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Viết như này ko sai, nhưng không khuyến khích |
||
|
|
||
| public function test_validation_fails_when_data_empty() | ||
| { | ||
| $request = new CheckoutRequest(); | ||
| $validator = Validator::make([], $request->rules()); | ||
|
|
||
| $this->assertTrue($validator->fails()); | ||
| } | ||
|
|
||
| public function test_validation_success() | ||
| { | ||
| $request = new CheckoutRequest(); | ||
| $validator = Validator::make([ | ||
| 'total_products' => [1 => 1, 2 => 2, 3 => 3], | ||
| ], $request->rules()); | ||
|
|
||
| $this->assertTrue($validator->passes()); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| <?php | ||
|
|
||
| namespace Modules\Exercise03\Tests\Feature\Models; | ||
|
|
||
| use Modules\Exercise03\Database\Factories\ProductFactory; | ||
| use Modules\Exercise03\Models\Product; | ||
| use Tests\SetupDatabaseTrait; | ||
| use Tests\TestCase; | ||
|
|
||
| class ProductTest extends TestCase | ||
| { | ||
| use SetupDatabaseTrait; | ||
|
|
||
| public function test_new_factory() | ||
| { | ||
| $product = Product::newFactory(); | ||
|
|
||
| $this->assertInstanceOf(ProductFactory::class, $product); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| <?php | ||
|
|
||
| namespace Tests\Unit\Repositories; | ||
|
|
||
| use Modules\Exercise03\Models\Product; | ||
| use Modules\Exercise03\Repositories\ProductRepository; | ||
| use Tests\TestCase; | ||
| use Illuminate\Database\Eloquent\Collection; | ||
|
|
||
| class ProductRepositoryTest extends TestCase | ||
| { | ||
| public function test__construct() | ||
| { | ||
| $product = new Product(); | ||
| $repository = new ProductRepository($product); | ||
|
|
||
| $this->assertInstanceOf(ProductRepository::class, $repository); | ||
| } | ||
|
|
||
| public function test_all() | ||
| { | ||
| $product = new Product(); | ||
| $repository = new ProductRepository($product); | ||
|
|
||
| $this->assertInstanceOf(Collection::class, $repository->all()); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| <?php | ||
|
|
||
| namespace Tests\Unit\Services; | ||
|
|
||
| use InvalidArgumentException; | ||
| use Modules\Exercise03\Repositories\ProductRepository; | ||
| use Modules\Exercise03\Services\ProductService; | ||
| use Tests\TestCase; | ||
|
|
||
| class ProductServiceTest extends TestCase | ||
| { | ||
| protected $productRepositoryMock; | ||
| protected $productService; | ||
|
|
||
| protected function setUp(): void | ||
| { | ||
| parent::setUp(); | ||
|
|
||
| // Laravel helper: mock and bind to service container | ||
| $this->productRepositoryMock = $this->mock(ProductRepository::class); | ||
| $this->productService = new ProductService($this->productRepositoryMock); | ||
|
|
||
| } | ||
|
|
||
| public function test__construct() | ||
| { | ||
| $this->assertInstanceOf(ProductService::class, $this->productService); | ||
| } | ||
|
|
||
| public function test_get_all_products() | ||
| { | ||
| $this->productRepositoryMock | ||
| ->shouldReceive('all') | ||
| ->andReturn([]); | ||
| $products = $this->productService->getAllProducts(); | ||
|
|
||
| $this->assertEquals($products, []); | ||
| } | ||
|
|
||
| /** | ||
| * @param $totalProducts | ||
| * @param $expectedValue | ||
| * @dataProvider provideValidTotalProductsData | ||
| * */ | ||
| public function test_calculate_discount_with_valid_data($totalProducts, $expectedValue) | ||
| { | ||
| $discount = $this->productService->calculateDiscount($totalProducts); | ||
| $this->assertEquals($expectedValue, $discount); | ||
| } | ||
|
|
||
| public function provideValidTotalProductsData() | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ở đây thiếu miss mất 1 case. Ngoài thì thì a cũng để ý các trương logic so sánh |
||
| { | ||
| return [ | ||
| [ | ||
| [ | ||
| 1 => 2, | ||
| 2 => 2, | ||
| 3 => 2, | ||
| ], 5 | ||
| ], | ||
| [ | ||
| [ | ||
| 1 => 0, | ||
| 2 => 4, | ||
| 3 => 4, | ||
| ], 7 | ||
| ], | ||
| [ | ||
| [ | ||
| 1 => 2, | ||
| 2 => 3, | ||
| 3 => 3, | ||
| ], 12 | ||
| ], | ||
| ]; | ||
| } | ||
|
Comment on lines
+40
to
+76
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Viết như này đọc khá khó hiểu, ít nhất nên đặt tên cho từng dataset hoặc là tách ra các case riêng biệt
Với cả thiếu case nhé? Anh thấy bài này có thể chia case theo kết quả mong muốn thì sẽ rất dễ sinh input, có 4 kết quả mong muốn:
Hoặc có thể bám theo lý thuyết C1 if ($cravat < 0 || $whiteShirt < 0 || $others < 0) {
// (1)
throw new InvalidArgumentException();
} // else (2)
if ($cravat > 0 && $whiteShirt > 0) {
// (3)
$discount = self::CRAVAT_WHITE_SHIRT_DISCOUNT;
} // else (4)
if (($cravat + $whiteShirt + $others) >= self::TOTAL_PRODUCT_TO_DISCOUNT) {
// (5)
$discount += self::QUANTITY_DISCOUNT;
} // else (6)
Và nên thêm 1 case để test cận cho điều kiện |
||
|
|
||
| /** | ||
| * @param $totalProducts | ||
| * @dataProvider provideInvalidTotalProductsData | ||
| * */ | ||
| public function test_exception_calculate_discount($totalProducts) | ||
| { | ||
| $this->expectException(InvalidArgumentException::class); | ||
| $this->productService->calculateDiscount($totalProducts); | ||
| } | ||
|
|
||
| public function provideInvalidTotalProductsData() | ||
| { | ||
| return [ | ||
| [ | ||
| [ | ||
| 1 => -1, | ||
| 2 => 2, | ||
| 3 => 2, | ||
| ], | ||
| ], | ||
| ]; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| <?php | ||
|
|
||
| namespace Modules\Exercise04\Tests\Feature\Http\Controllers; | ||
|
|
||
| use Modules\Exercise04\Http\Controllers\CalendarController; | ||
| use Modules\Exercise04\Services\CalendarService; | ||
| use Tests\TestCase; | ||
|
|
||
| class CalendarControllerTest extends TestCase | ||
| { | ||
| /** | ||
| * @var \Mockery\MockInterface | ||
| */ | ||
| protected $calendarServiceMock; | ||
|
|
||
| protected function setUp(): void | ||
| { | ||
| parent::setUp(); | ||
|
|
||
| // Laravel helper: mock and bind to service container | ||
| $this->calendarServiceMock = $this->mock(CalendarService::class); | ||
| } | ||
|
|
||
| /** | ||
| * A basic unit test example. | ||
| * | ||
| * @return void | ||
| */ | ||
| public function test__contruct() | ||
| { | ||
| $controller = new CalendarController($this->calendarServiceMock); | ||
|
|
||
| $this->assertInstanceOf(CalendarController::class, $controller); | ||
| } | ||
|
|
||
| public function test_index() | ||
| { | ||
| $this->calendarServiceMock->shouldReceive('getDateClass') | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Trong controller này có logic, nên phải làm sao test đưuọc cả logic đấy. Muốn test được logic đấy thì có 2 cách |
||
| ->andReturn(CalendarService::COLOR_BLUE); | ||
| $url = action([CalendarController::class, 'index']); | ||
|
|
||
| $response = $this->get($url); | ||
|
|
||
| $response->assertViewIs('exercise04::calendar'); | ||
| $response->assertViewHas('calendars'); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| <?php | ||
|
|
||
| namespace Tests\Unit\Services; | ||
|
|
||
| use Carbon\Carbon; | ||
| use Modules\Exercise04\Services\CalendarService; | ||
| use Tests\TestCase; | ||
|
|
||
| class CalendarServiceTest extends TestCase | ||
| { | ||
| protected $calendarService; | ||
|
|
||
| protected function setUp(): void | ||
| { | ||
| parent::setUp(); | ||
|
|
||
| $this->calendarService = new CalendarService(); | ||
| } | ||
|
|
||
| /** | ||
| * @param $date | ||
| * @param $expectedValue | ||
| * @dataProvider provideData | ||
| * */ | ||
| public function test_get_date_class($date, $expectedValue) | ||
| { | ||
| $holidays = ['2021-05-19']; | ||
|
|
||
| $class = $this->calendarService->getDateClass($date, $holidays); | ||
| $this->assertEquals($expectedValue, $class); | ||
| } | ||
|
|
||
| public function provideData() | ||
| { | ||
| return [ | ||
| 'Normal_day' => [ | ||
| Carbon::createFromDate(2021, 05, 18), | ||
| CalendarService::COLOR_BLACK | ||
| ], | ||
| 'Holiday' => [ | ||
| Carbon::createFromDate(2021, 05, 19), | ||
| CalendarService::COLOR_RED | ||
| ], | ||
| 'Saturday' => [ | ||
| Carbon::createFromDate(2021, 05, 22), | ||
| CalendarService::COLOR_BLUE | ||
| ], | ||
| 'Sunday' => [ | ||
| Carbon::createFromDate(2021, 05, 23), | ||
| CalendarService::COLOR_RED | ||
| ], | ||
| ]; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test constructor có ý nghĩa gì không em?