customerModel = $this->getMockBuilder(Customer::class) ->onlyMethods(['insert', 'getInsertID', 'update']) ->getMock(); $this->customerTypeModel = $this->getMockBuilder(SettingCustomerType::class) ->onlyMethods(['first']) ->addMethods(['where']) ->getMock(); $this->tierModel = $this->getMockBuilder(SettingMembershipTier::class) ->onlyMethods(['first']) ->addMethods(['where']) ->getMock(); // Set global POST input before request is retrieved service('request')->setGlobal('post', [ 'customer_type' => 'Regular', 'customer_tier' => 'Bronze', 'birthday' => '1990-01-01', 'phone' => '0123456789', 'email' => 'test@example.com', 'password_hash' => 'secret1234', 'name' => 'John Doe', ]); // Get request service AFTER setting global input $this->request = service('request'); $this->response = service('response'); // Now init the controller with the correct request/response $this->controller = new \App\Controllers\Backend\CustomerController(); $this->controller->initController($this->request, $this->response, service('logger')); // Inject mocks $this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $this->customerModel); $this->setProtectedOrPrivateProperty($this->controller, 'customerTypeModel', $this->customerTypeModel); $this->setProtectedOrPrivateProperty($this->controller, 'membershipTierModel', $this->tierModel); } //Have an issue protected function setProtectedOrPrivateProperty($object, $property, $value) { $reflection = new \ReflectionObject($object); while (!$reflection->hasProperty($property)) { $reflection = $reflection->getParentClass(); if (!$reflection) { throw new \Exception("Property {$property} does not exist"); } } $prop = $reflection->getProperty($property); $prop->setAccessible(true); $prop->setValue($object, $value); } public function testCreateFailsValidation() { $this->request->setGlobal('post', [ 'customer_type' => 'Regular', 'customer_tier' => 'Bronze', 'birthday' => '1990-01-01', 'phone' => '0123456789', 'email' => 'invalid-email', // Invalid email format 'password_hash' => 'secret1234', // 'name' is missing ]); $this->customerTypeModel->method('where')->willReturnSelf(); $this->customerTypeModel->method('first')->willReturn(['id' => 1, 'name' => 'Regular']); $this->tierModel->method('where')->willReturnSelf(); $this->tierModel->method('first')->willReturn(['id' => 2, 'name' => 'Bronze']); $this->setProtectedOrPrivateProperty($this->controller, 'request', $this->request); $response = $this->controller->create(); $this->assertEquals(400, $response->getStatusCode()); } public function testCreateFailsIfCustomerTypeNotFound() { // Inject mock validation to bypass default validation rules $mockValidation = $this->getMockBuilder(\CodeIgniter\Validation\Validation::class) ->disableOriginalConstructor() ->onlyMethods(['run', 'getErrors']) ->getMock(); $mockValidation->method('run')->willReturn(true); $mockValidation->method('getErrors')->willReturn([]); \Config\Services::injectMock('validation', $mockValidation); // $this->request = service('request'); $this->request->setGlobal('post', [ 'customer_type' => 'NonexistentType', // 'customer_tier' => 'Bronze', 'birthday' => '1990-01-01', 'phone' => '0123456789', 'email' => 'test@example.com', 'password_hash' => 'secret1234', 'name' => 'John Doe', ]); $this->customerTypeModel->method('where')->willReturnSelf(); $this->customerTypeModel->method('first')->willReturn(null); $this->setProtectedOrPrivateProperty($this->controller, 'request', $this->request); $response = $this->controller->create(); $this->assertEquals(404, $response->getStatusCode()); // $this->assertStringContainsString('Customer type', $response->getBody()); } public function testCreateFailsIfMembershipTierNotFound() { $mockValidation = $this->getMockBuilder(\CodeIgniter\Validation\Validation::class) ->disableOriginalConstructor() ->onlyMethods(['run', 'getErrors']) ->getMock(); $mockValidation->method('run')->willReturn(true); $mockValidation->method('getErrors')->willReturn([]); \Config\Services::injectMock('validation', $mockValidation); $this->request->setGlobal('post', [ 'customer_type' => 'Regular', 'customer_tier' => 'NonexistentTier', 'birthday' => '1990-01-01', 'phone' => '0123456789', 'email' => 'test@example.com', 'password_hash' => 'secret1234', 'name' => 'John Doe', ]); $this->customerTypeModel->method('where')->willReturnSelf(); $this->customerTypeModel->method('first')->willReturn(['id' => 1, 'name' => 'Regular']); $this->tierModel->method('where')->willReturnSelf(); $this->tierModel->method('first')->willReturn(null); $response = $this->controller->create(); $this->assertEquals(404, $response->getStatusCode()); } public function testCreateCustomerSuccess() { $mockValidation = $this->getMockBuilder(\CodeIgniter\Validation\Validation::class) ->disableOriginalConstructor() ->onlyMethods(['run', 'getErrors']) ->getMock(); $mockValidation->method('run')->willReturn(true); $mockValidation->method('getErrors')->willReturn([]); \Config\Services::injectMock('validation', $mockValidation); $this->request->setGlobal('post', [ 'customer_type' => 'Regular', 'customer_tier' => 'Bronze', 'birthday' => '1990-01-01', 'phone' => '0123456789', 'email' => 'test@example.com', 'password_hash' => 'secret1234', 'name' => 'John Doe', ]); $this->customerTypeModel->method('where')->willReturnSelf(); $this->customerTypeModel->method('first')->willReturn(['id' => 1, 'name' => 'Regular']); $this->tierModel->method('where')->willReturnSelf(); $this->tierModel->method('first')->willReturn(['id' => 2, 'name' => 'Bronze']); $this->customerModel->method('insert')->willReturn(true); $this->customerModel->method('getInsertID')->willReturn(5); $this->customerModel->method('update')->willReturn(true); // Inject a real response object $this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $this->customerModel); $this->setProtectedOrPrivateProperty($this->controller, 'customerTypeModel', $this->customerTypeModel); $this->setProtectedOrPrivateProperty($this->controller, 'membershipTierModel', $this->tierModel); $this->setProtectedOrPrivateProperty($this->controller, 'request', $this->request); $this->setProtectedOrPrivateProperty($this->controller, 'response', service('response')); $response = $this->controller->create(); // var_dump($response->getStatusCode()); // var_dump($response->getBody()); $this->assertEquals(200, $response->getStatusCode()); $this->assertStringContainsString('Customer created successfully', $response->getBody()); $_POST = []; } public function testCreateFailsOnCustomerInsert() { $mockValidation = $this->getMockBuilder(\CodeIgniter\Validation\Validation::class) ->disableOriginalConstructor() ->onlyMethods(['run', 'getErrors']) ->getMock(); $mockValidation->method('run')->willReturn(true); $mockValidation->method('getErrors')->willReturn([]); \Config\Services::injectMock('validation', $mockValidation); $this->request->setGlobal('post', [ 'customer_type' => 'Regular', 'customer_tier' => 'Bronze', 'birthday' => '1990-01-01', 'phone' => '0123456789', 'email' => 'test@example.com', 'password_hash' => 'secret1234', 'name' => 'John Doe', ]); // Mock success on lookups $this->customerTypeModel->method('where')->willReturnSelf(); $this->customerTypeModel->method('first')->willReturn(['id' => 1, 'name' => 'Regular']); $this->tierModel->method('where')->willReturnSelf(); $this->tierModel->method('first')->willReturn(['id' => 2, 'name' => 'Bronze']); // Simulate failure in DB insert $this->customerModel->method('insert')->willReturn(false); $this->setProtectedOrPrivateProperty($this->controller, 'request', $this->request); $response = $this->controller->create(); $this->assertEquals(500, $response->getStatusCode()); $this->assertStringContainsString('Failed to create customer', $response->getBody()); } public function testIndexReturnsCustomers() { $mockData = [ [ 'id' => 1, 'name' => 'Test Customer', 'customer_tier' => 'Gold', ], [ 'id' => 2, 'name' => 'Second Customer', 'customer_tier' => 'Silver', ] ]; $this->customerModel = $this->getMockBuilder(Customer::class) ->onlyMethods(['findAll']) ->addMethods(['select', 'join']) ->getMock(); $this->customerModel->method('select')->willReturnSelf(); $this->customerModel->method('join')->willReturnSelf(); $this->customerModel->method('findAll')->willReturn($mockData); $this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $this->customerModel); $response = $this->controller->index(); $this->assertSame(200, $response->getStatusCode()); $output = json_decode($response->getBody(), true); $this->assertEquals('success', $output['status']); $this->assertEquals('Customer list retrieved successfully.', $output['message']); $this->assertCount(2, $output['data']); $this->assertEquals('Test Customer', $output['data'][0]['name']); } public function testShowReturnsCustomerSuccess() { $mockCustomer = [ 'id' => 1, 'name' => 'Test Customer', 'email' => 'test@example.com', 'profile_picture' => null, 'customer_tier' => 'Gold', ]; $this->customerModel = $this->getMockBuilder(Customer::class) ->onlyMethods(['first']) ->addMethods(['select', 'join', 'where']) ->getMock(); $this->customerModel->method('select')->willReturnSelf(); $this->customerModel->method('join')->willReturnSelf(); $this->customerModel->method('where')->willReturnSelf(); $this->customerModel->method('first')->willReturn($mockCustomer); $this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $this->customerModel); $response = $this->controller->show(1); $this->assertSame(200, $response->getStatusCode()); $output = json_decode($response->getBody(), true); $this->assertEquals('success', $output['status']); $this->assertEquals('Customer retrieved successfully.', $output['message']); $this->assertEquals('Test Customer', $output['data']['name']); } public function testShowReturnsValidationErrorWhenIdMissing() { $this->setProtectedOrPrivateProperty($this->controller, 'response', service('response')); $response = $this->controller->show(null); $this->assertEquals(422, $response->getStatusCode()); $this->assertStringContainsString('Customer ID is required.', $response->getBody()); } public function testShowReturnsNotFoundWhenCustomerMissing() { $this->customerModel = $this->getMockBuilder(Customer::class) ->onlyMethods(['first']) ->addMethods(['select', 'join', 'where']) ->getMock(); $this->customerModel->method('select')->willReturnSelf(); $this->customerModel->method('join')->willReturnSelf(); $this->customerModel->method('where')->willReturnSelf(); $this->customerModel->method('first')->willReturn(null); $this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $this->customerModel); $response = $this->controller->show(99); // non-existing $this->assertSame(404, $response->getStatusCode()); $output = json_decode($response->getBody(), true); $this->assertEquals('error', $output['status']); $this->assertEquals('Customer with ID 99 not found.', $output['message']); } public function testDeleteCustomerFailsWithoutId() { $this->controller = new CustomerController(); $this->controller->initController(service('request'), service('response'), service('logger')); $result = $this->controller->delete(null); $output = json_decode($result->getJSON(), true); $this->assertEquals(422, $result->getStatusCode()); $this->assertEquals('error', $output['status']); $this->assertEquals('Customer ID is required.', $output['message']); $this->assertNull($output['data']); } public function testDeleteCustomerFailsWhenNotFound() { $this->customerModel = $this->getMockBuilder(Customer::class) ->onlyMethods(['find']) ->getMock(); $this->customerModel->method('find')->willReturn(null); $this->controller = new CustomerController(); $this->controller->initController(service('request'), service('response'), service('logger')); $this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $this->customerModel); $result = $this->controller->delete(999); $output = json_decode($result->getJSON(), true); $this->assertEquals(404, $result->getStatusCode()); $this->assertEquals('error', $output['status']); $this->assertEquals('Customer with ID 999 not found.', $output['message']); $this->assertNull($output['data']); } public function testDeleteCustomerSuccess() { $mockCustomer = ['id' => 1, 'name' => 'Test User']; $this->customerModel = $this->getMockBuilder(Customer::class) ->onlyMethods(['find', 'delete']) ->getMock(); $this->customerModel->method('find')->with(1)->willReturn($mockCustomer); $this->customerModel->method('delete')->with(1)->willReturn(true); $this->controller = new CustomerController(); $this->controller->initController(service('request'), service('response'), service('logger')); $this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $this->customerModel); $result = $this->controller->delete(1); $output = json_decode($result->getJSON(), true); $this->assertEquals(200, $result->getStatusCode()); $this->assertEquals('success', $output['status']); $this->assertEquals('Customer with ID 1 deleted successfully.', $output['message']); $this->assertNull($output['data']); } public function testUpdateFailsOnValidationError() { $id = 1; $mockCustomerModel = $this->createMock(\App\Models\Customer::class); $mockCustomerModel->method('find')->willReturn([ 'id' => $id, 'phone' => '0123456789', 'email' => 'test@example.com' ]); $this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $mockCustomerModel); $this->request->setGlobal('post', [ 'customer_type' => 'Regular', 'customer_tier' => 'Bronze', 'birthday' => '1990-01-01', 'phone' => '0123456789', 'email' => 'test@example.com', 'name' => '', // Empty name = fail ]); $this->setProtectedOrPrivateProperty($this->controller, 'request', $this->request); $response = $this->controller->update($id); $this->assertEquals(422, $response->getStatusCode()); $this->assertStringContainsString('Validation failed', $response->getBody()); } public function testUpdateCustomerSuccess() { // Mock customer ID $customerId = 1; // Expected customer data returned by find() $existingCustomer = [ 'id' => $customerId, 'name' => 'Old Name', 'phone' => '0111111111', 'email' => 'old@example.com', 'customer_type' => 'Regular', 'membership_tier' => 'Silver', 'birthday' => '1990-01-01', ]; // Create mock for Customer model $mockCustomerModel = $this->createMock(Customer::class); $mockCustomerModel->method('find')->with($customerId)->willReturn($existingCustomer); $mockCustomerModel->method('update')->willReturn(true); // Mock SettingCustomerType model $mockCustomerTypeModel = $this->getMockBuilder(SettingCustomerType::class) ->onlyMethods(['first']) // first() exists — use onlyMethods() ->addMethods(['where']) // where() is dynamic — use addMethods() ->getMock(); $mockCustomerTypeModel->method('where')->willReturnSelf(); $mockCustomerTypeModel->method('first')->willReturn(['name' => 'Regular']); // Mock SettingMembershipTier model $mockTierModel = $this->getMockBuilder(SettingMembershipTier::class) ->onlyMethods(['first']) // first() exists — use onlyMethods() ->addMethods(['where']) // where() is dynamic — use addMethods() ->getMock(); $mockTierModel->method('where')->willReturnSelf(); $mockTierModel->method('first')->willReturn([ 'id' => 1, 'name' => 'Gold' ]); // Mock the IncomingRequest $mockRequest = $this->getMockBuilder(IncomingRequest::class) ->disableOriginalConstructor() ->onlyMethods(['getVar', 'getMethod']) ->getMock(); $mockRequest->method('getVar')->willReturnCallback(function ($key) { $data = [ 'id' => 1, 'phone' => '0123456789', 'name' => 'Updated Name', 'email' => 'updated@example.com', 'customer_type' => 'Regular', 'membership_tier' => 'Gold', 'birthday' => '1990-01-01', ]; return $data[$key] ?? null; }); $mockRequest->method('getMethod')->willReturn('post'); // Mock validation to return true (skip validation errors) $mockValidation = $this->getMockBuilder(\CodeIgniter\Validation\Validation::class) ->disableOriginalConstructor() ->onlyMethods(['run', 'getErrors']) ->getMock(); $mockValidation->method('run')->willReturn(true); $mockValidation->method('getErrors')->willReturn([]); \Config\Services::injectMock('validation', $mockValidation); // Create controller and inject mocks $controller = new CustomerController(); $this->setProtectedOrPrivateProperty($controller, 'request', $mockRequest); $this->setProtectedOrPrivateProperty($controller, 'customerModel', $mockCustomerModel); $this->setProtectedOrPrivateProperty($controller, 'customerTypeModel', $mockCustomerTypeModel); $this->setProtectedOrPrivateProperty($controller, 'membershipTierModel', $mockTierModel); $this->setProtectedOrPrivateProperty($controller, 'response', \Config\Services::response()); // Run update $response = $controller->update($customerId); // $statusCode = $response->getStatusCode(); // $body = $response->getBody(); // var_dump($statusCode); // var_dump($body); // Assert success $this->assertSame(200, $response->getStatusCode()); } public function testUpdateFailsWhenCustomerNotFound() { $mockCustomerModel = $this->createMock(\App\Models\Customer::class); $mockCustomerModel->method('find')->willReturn(null); $this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $mockCustomerModel); $response = $this->controller->update(999); // Non-existent ID $this->assertEquals(404, $response->getStatusCode()); $this->assertStringContainsString('Customer with ID 999 not found', $response->getBody()); } public function testUpdateFailsIfTierNotFound() { $id = 1; // Mock customerModel $mockCustomerModel = $this->createMock(\App\Models\Customer::class); $mockCustomerModel->method('find')->willReturn([ 'id' => $id, 'phone' => '0123456789', 'email' => 'test@example.com', ]); // Mock membershipTierModel to return null (tier not found) $mockTierModel = $this->getMockBuilder(SettingMembershipTier::class) ->onlyMethods(['first']) ->addMethods(['where']) ->getMock(); $mockTierModel->method('where')->willReturnSelf(); $mockTierModel->method('first')->willReturn(null); // Set mocked models into the controller $this->setProtectedOrPrivateProperty($this->controller, 'customerModel', $mockCustomerModel); $this->setProtectedOrPrivateProperty($this->controller, 'membershipTierModel', $mockTierModel); // Create and mock a request with POST data $mockRequest = $this->getMockBuilder(IncomingRequest::class) ->disableOriginalConstructor() ->onlyMethods(['getVar', 'getMethod']) ->getMock(); $mockRequest->method('getVar')->willReturnMap([ ['customer_type', null, 'Regular'], ['customer_tier', null, 'NonexistentTier'], ['birthday', null, '1990-01-01'], ['phone', null, '0123456789'], ['email', null, 'test@example.com'], ['name', null, 'John Doe'], ]); $mockRequest->method('getMethod')->willReturn('post'); // Set the mocked request into the controller $this->setProtectedOrPrivateProperty($this->controller, 'request', $mockRequest); // Mock validation to return true (skip validation errors) $mockValidation = $this->getMockBuilder(\CodeIgniter\Validation\Validation::class) ->disableOriginalConstructor() ->onlyMethods(['run', 'getErrors']) ->getMock(); $mockValidation->method('run')->willReturn(true); $mockValidation->method('getErrors')->willReturn([]); \Config\Services::injectMock('validation', $mockValidation); // Call the update method $response = $this->controller->update($id); // Assertions $this->assertEquals(404, $response->getStatusCode()); } }