diff --git a/Modules/Exercise03/Tests/Feature/Http/Controllers/ProductControllerTest.php b/Modules/Exercise03/Tests/Feature/Http/Controllers/ProductControllerTest.php
new file mode 100644
index 0000000..d215839
--- /dev/null
+++ b/Modules/Exercise03/Tests/Feature/Http/Controllers/ProductControllerTest.php
@@ -0,0 +1,60 @@
+productService = \Mockery::mock(ProductService::class);
+ $this->productController = new ProductController(
+ $this->productService
+ );
+ }
+
+ /**
+ * A basic feature test example.
+ *
+ * @return void
+ */
+ public function testIndex()
+ {
+ $products = [
+ 'name' => 'name',
+ 'status' => 1
+ ];
+
+ $this->productService->shouldReceive('getAllProducts')
+ ->andReturn($products);
+ $response = $this->productController->index();
+ $this->assertInstanceOf(View::class, $response);
+ $this->assertEquals('exercise03::index', $response->getName());
+ }
+
+ public function testCheckout() {
+ $input['total_products'] = [
+ 1 => 1,
+ 2 => 2,
+ 3 => 3
+ ];
+
+ $this->productService->shouldReceive('calculateDiscount')
+ ->with($input)
+ ->andReturn(5);
+ $mockRequest = \Mockery::mock(CheckoutRequest::class);
+ $mockRequest->shouldReceive('input')->andReturn($input);
+ $response = $this->productController->checkout($mockRequest);
+ $this->assertEquals(['discount' => 5], $response->getOriginalContent());
+ }
+}
diff --git a/Modules/Exercise03/Tests/Feature/Http/Requests/CheckoutRequestTest.php b/Modules/Exercise03/Tests/Feature/Http/Requests/CheckoutRequestTest.php
new file mode 100644
index 0000000..b0be8c3
--- /dev/null
+++ b/Modules/Exercise03/Tests/Feature/Http/Requests/CheckoutRequestTest.php
@@ -0,0 +1,45 @@
+request = new CheckoutRequest();
+ }
+
+ public function testRules()
+ {
+ $this->assertEquals([
+ 'total_products' => 'required|array',
+ 'total_products.*' => 'nullable|integer|min:0',
+ ],
+ $this->request->rules()
+ );
+ }
+
+ public function testInvalidData()
+ {
+ $validator = Validator::make([], $this->request->rules());
+ $this->assertTrue($validator->fails());
+ }
+
+ public function testValidData()
+ {
+ $data = [
+ 'total_products' => [0, 1, 2, 3],
+ ];
+
+ $validator = Validator::make($data, $this->request->rules());
+ $this->assertTrue($validator->passes());
+ }
+}
diff --git a/Modules/Exercise03/Tests/Feature/Models/ProductTest.php b/Modules/Exercise03/Tests/Feature/Models/ProductTest.php
new file mode 100644
index 0000000..eb5f957
--- /dev/null
+++ b/Modules/Exercise03/Tests/Feature/Models/ProductTest.php
@@ -0,0 +1,20 @@
+make();
+ $this->assertInstanceOf(Product::class, $product);
+ }
+}
diff --git a/Modules/Exercise03/Tests/Feature/Repositories/ProductRepositoryTest.php b/Modules/Exercise03/Tests/Feature/Repositories/ProductRepositoryTest.php
new file mode 100644
index 0000000..e79e041
--- /dev/null
+++ b/Modules/Exercise03/Tests/Feature/Repositories/ProductRepositoryTest.php
@@ -0,0 +1,23 @@
+all();
+ $this->assertInstanceOf(Collection::class, $getAll);
+ }
+}
diff --git a/Modules/Exercise03/Tests/Feature/Services/ProductServiceTest.php b/Modules/Exercise03/Tests/Feature/Services/ProductServiceTest.php
new file mode 100644
index 0000000..2951fc0
--- /dev/null
+++ b/Modules/Exercise03/Tests/Feature/Services/ProductServiceTest.php
@@ -0,0 +1,104 @@
+mockProductRepository = $this->mock(ProductRepository::class);
+ $this->productService = new ProductService($this->mockProductRepository);
+ }
+
+ /**
+ * @dataProvider provideData
+ */
+
+ public function testCalculateDiscount($totalProducts, $expectValue, $testCase = 'OK')
+ {
+ if ($testCase === 'NG') {
+ $this->expectException(InvalidArgumentException::class);
+ }
+
+ $response = $this->productService->calculateDiscount($totalProducts);
+ $this->assertEquals($response, $expectValue);
+ }
+
+ public function provideData()
+ {
+ return [
+ [
+ [
+ 1 => 0,
+ 2 => 0,
+ 3 => 0
+ ],
+ 0
+ ],
+ [
+ [
+ 1 => 1,
+ 2 => 2,
+ 3 => 2
+ ],
+ 5
+ ],
+ [
+ [
+ 1 => 1,
+ 2 => 0,
+ 3 => 7
+ ],
+ 7
+ ],
+ [
+ [
+ 1 => 1,
+ 2 => 2,
+ 3 => 5
+ ],
+ 12
+ ],
+ [
+ [
+ 1 => -1,
+ 2 => 2,
+ 3 => 9
+ ],
+ 0,
+ 'NG'
+ ],
+ [
+ [
+ 1 => 1,
+ 2 => -2,
+ 3 => 2
+ ],
+ 0,
+ 'NG'
+ ],
+ ];
+ }
+
+ public function testGetAllProducts()
+ {
+ $this->mockProductRepository
+ ->shouldReceive('all')
+ ->andReturn([]);
+
+ $this->assertEquals($this->productService->getAllProducts(), []);
+ }
+
+}
diff --git a/Modules/Exercise04/Tests/Feature/Http/Controllers/CalendarControllerTest.php b/Modules/Exercise04/Tests/Feature/Http/Controllers/CalendarControllerTest.php
new file mode 100644
index 0000000..4c1067f
--- /dev/null
+++ b/Modules/Exercise04/Tests/Feature/Http/Controllers/CalendarControllerTest.php
@@ -0,0 +1,33 @@
+mockCalendarService = $this->mock(CalendarService::class);
+ $this->calendarController = new CalendarController($this->mockCalendarService);
+ }
+
+ public function testIndex()
+ {
+ $this->mockCalendarService
+ ->shouldReceive('getDateClass')
+ ->andReturn(CalendarService::COLOR_BLUE);
+
+ $response = $this->calendarController->index();
+ $this->assertInstanceOf(View::class, $response);
+ $this->assertEquals('exercise04::calendar', $response->getName());
+ }
+
+}
diff --git a/Modules/Exercise04/Tests/Feature/Http/Services/CalendarServiceTest.php b/Modules/Exercise04/Tests/Feature/Http/Services/CalendarServiceTest.php
new file mode 100644
index 0000000..3125720
--- /dev/null
+++ b/Modules/Exercise04/Tests/Feature/Http/Services/CalendarServiceTest.php
@@ -0,0 +1,53 @@
+calendarService = new CalendarService();
+ }
+
+ /**
+ * @param $date
+ * @dataProvider provideData
+ */
+ public function testGetDateClass($date, $expectValue)
+ {
+ $holiday = ['2021-05-30'];
+
+ $class = $this->calendarService->getDateClass($date, $holiday);
+ $this->assertEquals($class, $expectValue);
+ }
+
+ public function provideData()
+ {
+ return [
+ [
+ Carbon::createFromDate(2021, 5, 23),
+ CalendarService::COLOR_RED,
+ ],
+ [
+ Carbon::createFromDate(2021, 5, 29),
+ CalendarService::COLOR_BLUE,
+ ],
+ [
+ Carbon::createFromDate(2021, 5, 30),
+ CalendarService::COLOR_RED,
+ ],
+ [
+ Carbon::createFromDate(2021, 6, 30),
+ CalendarService::COLOR_BLACK,
+ ],
+
+ ];
+ }
+}
diff --git a/Modules/Exercise05/Tests/Feature/Http/Controllers/Exercise05ControllerTest.php b/Modules/Exercise05/Tests/Feature/Http/Controllers/Exercise05ControllerTest.php
new file mode 100644
index 0000000..818313f
--- /dev/null
+++ b/Modules/Exercise05/Tests/Feature/Http/Controllers/Exercise05ControllerTest.php
@@ -0,0 +1,50 @@
+mockOrderService = $this->mock(OrderService::class);
+ $this->controller = new Exercise05Controller($this->mockOrderService);
+ }
+
+ public function testIndex()
+ {
+ $response = $this->controller->index();
+ $this->assertInstanceOf(View::class, $response);
+ $this->assertEquals('exercise05::index', $response->getName());
+ }
+
+ public function testStore()
+ {
+ $detailOrder = [
+ 'price' => 100,
+ 'option_receive' => 1,
+ 'option_coupon' => 1
+ ];
+
+ $mockRequest = $this->mock(OrderRequest::class);
+ $mockRequest->shouldReceive('only')
+ ->andReturn($detailOrder);
+
+ $this->mockOrderService
+ ->shouldReceive('handleDiscount')
+ ->andReturn(1);
+
+ $res = $this->controller->store($mockRequest);
+ $this->assertEquals('exercise05::detail', $res->getName());
+ }
+}
diff --git a/Modules/Exercise05/Tests/Feature/Http/Requests/OrderRequestTest.php b/Modules/Exercise05/Tests/Feature/Http/Requests/OrderRequestTest.php
new file mode 100644
index 0000000..4fb39aa
--- /dev/null
+++ b/Modules/Exercise05/Tests/Feature/Http/Requests/OrderRequestTest.php
@@ -0,0 +1,67 @@
+request = new OrderRequest();
+ }
+
+ /**
+ * @dataProvider providerData
+ */
+ public function testRules($data, $testCase = 'NG')
+ {
+ $validator = Validator::make($data, $this->request->rules());
+
+ if ($testCase === 'OK') {
+ $this->assertTrue($validator->passes());
+ } else {
+ $this->assertTrue($validator->fails());
+ }
+ }
+
+ public function providerData()
+ {
+ return [
+ // Invalid data
+ [$this->makeData()],
+ // price: invalid
+ [$this->makeData('String', 1, 1)],
+ [$this->makeData('100,000', 1, 1)],
+ // option_receive: invalid
+ [$this->makeData(100, null, 1)],
+ [$this->makeData(100, 0, 1)],
+ [$this->makeData(100, 3, 1)],
+ //option_coupon: invalid
+ [$this->makeData(100, null, 0)],
+ [$this->makeData(100, 1, 0)],
+ [$this->makeData(100, 1, 3)],
+
+ // Valid data
+ [$this->makeData(100, 1, 1), 'OK'],
+ [$this->makeData(100, 2, 1), 'OK'],
+ [$this->makeData(100, 1, 1), 'OK'],
+ [$this->makeData(100.000, 1, 2), 'OK'],
+ ];
+ }
+
+ public function makeData($price = null, $optionReceive = null, $optionCoupon = null)
+ {
+ return [
+ 'price' => $price,
+ 'option_receive' => $optionReceive,
+ 'option_coupon' => $optionCoupon
+ ];
+ }
+}
diff --git a/Modules/Exercise05/Tests/Feature/Http/Services/OrderServiceTest.php b/Modules/Exercise05/Tests/Feature/Http/Services/OrderServiceTest.php
new file mode 100644
index 0000000..1cd8c42
--- /dev/null
+++ b/Modules/Exercise05/Tests/Feature/Http/Services/OrderServiceTest.php
@@ -0,0 +1,67 @@
+orderService = new OrderService();
+ }
+
+ /**
+ * @dataProvider provideData
+ */
+ public function testHandleDiscount($detailOrder, $expectValue)
+ {
+ $response = $this->orderService->handleDiscount($detailOrder);
+
+ $this->assertEquals($response, $expectValue);
+ }
+
+ public function provideData()
+ {
+ return [
+ [
+ $this->makeData(1501, 1, 2),
+ $this->makeBill(1501, 'Khuyến mại pizza thứ 2', 'Miễn phí khoai tây')
+ ],
+ [
+ $this->makeData(1600, 2, 1),
+ $this->makeBill(1280, null, 'Miễn phí khoai tây')
+ ],
+ [
+ $this->makeData(1400, 2, 2),
+ $this->makeBill(1400, null, null)
+ ],
+ [
+ $this->makeData(1400, 1, 3),
+ $this->makeBill(1400, 'Khuyến mại pizza thứ 2', null)
+ ],
+ ];
+ }
+
+ public function makeData($price = null, $optionReceive = null, $optionCoupon = null)
+ {
+ return [
+ 'price' => $price,
+ 'option_receive' => $optionReceive,
+ 'option_coupon' => $optionCoupon,
+ ];
+ }
+
+ public function makeBill($price = null, $discountPizza = null, $discountCoupon = null)
+ {
+ return [
+ 'price' => $price,
+ 'discount_pizza' => $discountPizza,
+ 'discount_potato' => $discountCoupon,
+ ];
+ }
+}
diff --git a/Modules/Exercise06/Tests/Feature/Http/Controllers/Exercise06ControllerTest.php b/Modules/Exercise06/Tests/Feature/Http/Controllers/Exercise06ControllerTest.php
new file mode 100644
index 0000000..01dea60
--- /dev/null
+++ b/Modules/Exercise06/Tests/Feature/Http/Controllers/Exercise06ControllerTest.php
@@ -0,0 +1,50 @@
+mockCalculateService = $this->mock(CalculateService::class);
+ $this->controller = new Exercise06Controller($this->mockCalculateService);
+ }
+
+ public function testIndex()
+ {
+ $response = $this->controller->index();
+ $this->assertInstanceOf(View::class, $response);
+ $this->assertEquals('exercise06::index', $response->getName());
+ }
+
+ public function testCalculate()
+ {
+ $input = [
+ 'bill' => 2021,
+ 'has_watch' => true,
+ ];
+
+ $mockRequest = $this->mock(Exercise06Request::class);
+ $mockRequest->shouldReceive('validated')
+ ->andReturn($input);
+
+ $this->mockCalculateService->shouldReceive('calculate')
+ ->with($input['bill'], $input['has_watch'])
+ ->andReturn(60);
+
+ $res = $this->controller->calculate($mockRequest);
+ $this->assertInstanceOf(RedirectResponse::class, $res);
+ }
+}
diff --git a/Modules/Exercise06/Tests/Feature/Http/Requests/Exercise06RequestTest.php b/Modules/Exercise06/Tests/Feature/Http/Requests/Exercise06RequestTest.php
new file mode 100644
index 0000000..95b6552
--- /dev/null
+++ b/Modules/Exercise06/Tests/Feature/Http/Requests/Exercise06RequestTest.php
@@ -0,0 +1,44 @@
+request = new Exercise06Request();
+ }
+
+ /**
+ * @dataProvider providerData
+ */
+ public function testRules($data, $testCase = 'NG')
+ {
+ $validator = Validator::make($data, $this->request->rules());
+
+ if ($testCase == 'OK') {
+ $this->assertTrue($validator->passes());
+ } else {
+ $this->assertTrue($validator->fails());
+ }
+ }
+
+ public function providerData()
+ {
+ return [
+ [['bill' => null, 'has_watch' => null]],
+ [['bill' => -1, 'has_watch' => null]],
+ [['bill' => 1, 'has_watch' => 123]],
+ [['bill' => 'string', 'has_watch' => true]],
+ [['bill' => 1, 'has_watch' => true], 'OK'],
+ ];
+ }
+}
diff --git a/Modules/Exercise06/Tests/Feature/Services/CalculateServiceTest.php b/Modules/Exercise06/Tests/Feature/Services/CalculateServiceTest.php
new file mode 100644
index 0000000..a96b2f7
--- /dev/null
+++ b/Modules/Exercise06/Tests/Feature/Services/CalculateServiceTest.php
@@ -0,0 +1,50 @@
+calculateService = new CalculateService();
+ }
+
+ /**
+ * @dataProvider provideData
+ */
+ public function testCalculate($params, $expectValue, $testCase = 'OK')
+ {
+ if ($testCase == 'NG') {
+ $this->expectException(InvalidArgumentException::class);
+ }
+
+ $response = $this->calculateService->calculate($params['bill'], $params['hasWatch']);
+ $this->assertEquals($response, $expectValue);
+ }
+
+ public function provideData()
+ {
+ return [
+ [$this->makeData(2021, false), 60],
+ [$this->makeData(5001, false), 120],
+ [$this->makeData(2021, true), 240],
+ [$this->makeData(5001, true), 300],
+ [$this->makeData(-1, true), 0, 'NG'],
+ ];
+ }
+
+ public function makeData($bill = null, $hasWatch = null)
+ {
+ return [
+ 'bill' => $bill,
+ 'hasWatch' => $hasWatch,
+ ];
+ }
+}
diff --git a/Modules/Exercise07/Tests/Feature/Http/Controllers/CheckoutControllerTest.php b/Modules/Exercise07/Tests/Feature/Http/Controllers/CheckoutControllerTest.php
new file mode 100644
index 0000000..3d1be87
--- /dev/null
+++ b/Modules/Exercise07/Tests/Feature/Http/Controllers/CheckoutControllerTest.php
@@ -0,0 +1,50 @@
+mockCheckoutService = $this->mock(CheckoutService::class);
+ $this->controller = new CheckoutController($this->mockCheckoutService);
+ }
+
+ public function testIndex()
+ {
+ $response = $this->controller->index();
+ $this->assertInstanceOf(View::class, $response);
+ $this->assertEquals('exercise07::checkout.index', $response->getName());
+ }
+
+ public function testStore()
+ {
+ $order = [
+ 'amount' => 1000,
+ 'shipping_express' => true,
+ ];
+
+ $mockRequest = $this->mock(CheckoutRequest::class);
+ $mockRequest->shouldReceive('all')
+ ->andReturn($order);
+
+ $this->mockCheckoutService->shouldReceive('calculateShippingFee')
+ ->with($order)
+ ->andReturn([]);
+
+ $res = $this->controller->store($mockRequest);
+ $this->assertInstanceOf(RedirectResponse::class, $res);
+ }
+}
diff --git a/Modules/Exercise07/Tests/Feature/Http/Requests/CheckoutRequestTest.php b/Modules/Exercise07/Tests/Feature/Http/Requests/CheckoutRequestTest.php
new file mode 100644
index 0000000..63ec6af
--- /dev/null
+++ b/Modules/Exercise07/Tests/Feature/Http/Requests/CheckoutRequestTest.php
@@ -0,0 +1,45 @@
+request = new CheckoutRequest();
+ }
+
+ /**
+ * @dataProvider providerData
+ */
+ public function testRules($data, $testCase = 'NG')
+ {
+ $validator = Validator::make([
+ 'amount' => $data['amount'],
+ ], $this->request->rules());
+
+ if ($testCase == 'OK') {
+ $this->assertTrue($validator->passes());
+ } else {
+ $this->assertTrue($validator->fails());
+ }
+ }
+
+ public function providerData()
+ {
+ return [
+ [['amount' => null]],
+ [['amount' => 0]],
+ [['amount' => -1]],
+ [['amount' => 100], 'OK'],
+ ];
+ }
+}
diff --git a/Modules/Exercise07/Tests/Feature/Services/CheckoutServiceTest.php b/Modules/Exercise07/Tests/Feature/Services/CheckoutServiceTest.php
new file mode 100644
index 0000000..fe0bd08
--- /dev/null
+++ b/Modules/Exercise07/Tests/Feature/Services/CheckoutServiceTest.php
@@ -0,0 +1,55 @@
+checkoutService = new CheckoutService();
+ }
+
+ /**
+ * @dataProvider provideData
+ */
+ public function testCalculateShippingFee($order, $expectValue, $testCase = 'OK')
+ {
+ $response = $this->checkoutService->calculateShippingFee($order);
+ $this->assertEquals($response, $expectValue);
+ }
+
+ public function provideData()
+ {
+ return [
+ [
+ $this->makeOrder(5000, null),
+ $this->makeOrder(5000, null, 0)
+ ],
+ [
+ $this->makeOrder(5001, null),
+ $this->makeOrder(5001, null, 0)
+ ],
+ [
+ $this->makeOrder(4999, null, null, 'premium_member'),
+ $this->makeOrder(4999, null, 0, 'premium_member')
+ ],
+ ];
+ }
+
+ public function makeOrder($amount, $express, $fee = null, $premiumMember = null)
+ {
+ return [
+ 'amount' => $amount,
+ 'shipping_express' => $express,
+ 'shipping_fee' => $fee,
+ 'premium_member' => $premiumMember
+ ];
+ }
+}
diff --git a/infection.json b/infection.json
index 0c8fa89..b436b48 100644
--- a/infection.json
+++ b/infection.json
@@ -1,7 +1,11 @@
{
"source": {
"directories": [
- "Modules/"
+ "Modules/Exercise03/",
+ "Modules/Exercise04/",
+ "Modules/Exercise05/",
+ "Modules/Exercise06/",
+ "Modules/Exercise07/"
],
"excludes": [
"Config",
diff --git a/phpunit.xml b/phpunit.xml
index 77442f0..9242f5c 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -6,9 +6,11 @@
>
- ./tests/Unit
- ./tests/Feature
- ./Modules/**/Tests
+ ./Modules/Exercise03/Tests
+ ./Modules/Exercise04/Tests
+ ./Modules/Exercise05/Tests
+ ./Modules/Exercise06/Tests
+ ./Modules/Exercise07/Tests
./Modules/Exercise01/Tests
@@ -43,8 +45,11 @@
- ./app
- ./Modules
+ ./Modules/Exercise03
+ ./Modules/Exercise04
+ ./Modules/Exercise05
+ ./Modules/Exercise06
+ ./Modules/Exercise07
./Modules/**/Config