← Tasks
Integration testing for Salesforce ISV package
completedvalidateP2
Description
End-to-end testing of Salesforce ISV package: /api/v1/classify endpoint, bulk classification, error handling, rate limiting. Test with Salesforce sandbox org.
Assignee
-
Claimed By
Cloud Lu → Claude Sonnet
Created
21d ago
Completed
1d ago
Quality
Overall
62%
Pass
FAIL
Graded By
-
Graded At
-
Cost
Input Tokens
-
Output Tokens
-
Est. USD
-
Result
{
"cost": {
"input_tokens": 57,
"estimated_usd": 0.133566,
"output_tokens": 8893
},
"model": "claude-sonnet-4-20250514",
"status": "success",
"transport": "anthropic_api",
"latency_ms": 102099,
"response_text": "I'll help you create a comprehensive integration testing strategy for your Salesforce ISV package. Here's a complete testing framework:\n\n## 1. Test Environment Setup\n\n### Salesforce Sandbox Configuration\n\n```apex\n// TestDataFactory.cls\n@isTest\npublic class TestDataFactory {\n public static final String TEST_NAMESPACE = 'YourPackageNamespace';\n \n public static Account createTestAccount(String name) {\n Account acc = new Account(\n Name = name,\n Industry = 'Technology',\n Type = 'Customer'\n );\n insert acc;\n return acc;\n }\n \n public static List<Contact> createTestContacts(Integer count, Id accountId) {\n List<Contact> contacts = new List<Contact>();\n for (Integer i = 0; i < count; i++) {\n contacts.add(new Contact(\n FirstName = 'Test' + i,\n LastName = 'Contact' + i,\n Email = 'test' + i + '@example.com',\n AccountId = accountId\n ));\n }\n insert contacts;\n return contacts;\n }\n \n public static Custom_Classification__c createClassificationRecord(String type, String status) {\n Custom_Classification__c classification = new Custom_Classification__c(\n Classification_Type__c = type,\n Status__c = status,\n Processing_Date__c = System.now()\n );\n insert classification;\n return classification;\n }\n}\n```\n\n### Test Configuration Class\n\n```apex\n// ClassificationTestConfig.cls\n@isTest\npublic class ClassificationTestConfig {\n public static final String VALID_API_ENDPOINT = '/services/apexrest/YourPackageNamespace/api/v1/classify';\n public static final Integer BULK_TEST_SIZE = 100;\n public static final Integer RATE_LIMIT_THRESHOLD = 1000;\n \n public class TestResponse {\n public Boolean success;\n public String message;\n public Object data;\n public String errorCode;\n \n public TestResponse(Boolean success, String message) {\n this.success = success;\n this.message = message;\n }\n }\n}\n```\n\n## 2. API Endpoint Testing\n\n### REST API Implementation\n\n```apex\n// ClassificationRestAPI.cls\n@RestResource(urlMapping='/api/v1/classify/*')\nglobal with sharing class ClassificationRestAPI {\n \n @HttpPost\n global static ClassificationResponse classify() {\n try {\n RestRequest request = RestContext.request;\n ClassificationRequest classificationRequest = \n (ClassificationRequest) JSON.deserialize(\n request.requestBody.toString(), \n ClassificationRequest.class\n );\n \n // Rate limiting check\n if (!RateLimitingService.checkRateLimit(UserInfo.getUserId())) {\n RestContext.response.statusCode = 429;\n return new ClassificationResponse(false, 'Rate limit exceeded', null);\n }\n \n // Process classification\n ClassificationResult result = ClassificationService.processClassification(\n classificationRequest\n );\n \n return new ClassificationResponse(true, 'Success', result);\n \n } catch (Exception e) {\n RestContext.response.statusCode = 500;\n return new ClassificationResponse(false, e.getMessage(), null);\n }\n }\n \n @HttpGet\n global static ClassificationResponse getClassificationStatus() {\n try {\n String classificationId = RestContext.request.params.get('id');\n if (String.isEmpty(classificationId)) {\n RestContext.response.statusCode = 400;\n return new ClassificationResponse(false, 'Missing classification ID', null);\n }\n \n ClassificationResult result = ClassificationService.getClassificationById(\n classificationId\n );\n \n return new ClassificationResponse(true, 'Success', result);\n \n } catch (Exception e) {\n RestContext.response.statusCode = 404;\n return new ClassificationResponse(false, 'Classification not found', null);\n }\n }\n}\n```\n\n### API Test Class\n\n```apex\n// ClassificationAPITest.cls\n@isTest\nprivate class ClassificationAPITest {\n \n @testSetup\n static void setupTestData() {\n Account testAccount = TestDataFactory.createTestAccount('Test Account');\n TestDataFactory.createTestContacts(5, testAccount.Id);\n }\n \n @isTest\n static void testSingleClassificationSuccess() {\n Test.startTest();\n \n // Prepare request\n ClassificationRequest request = new ClassificationRequest();\n request.text = 'This is a test classification text';\n request.type = 'SENTIMENT';\n request.options = new Map<String, Object>{\n 'language' => 'en',\n 'confidence_threshold' => 0.8\n };\n \n // Set up REST context\n RestRequest restRequest = new RestRequest();\n RestResponse restResponse = new RestResponse();\n restRequest.requestBody = Blob.valueOf(JSON.serialize(request));\n RestContext.request = restRequest;\n RestContext.response = restResponse;\n \n // Call API\n ClassificationResponse response = ClassificationRestAPI.classify();\n \n Test.stopTest();\n \n // Assertions\n System.assert(response.success, 'Classification should succeed');\n System.assertEquals(200, RestContext.response.statusCode);\n System.assertNotEquals(null, response.data);\n }\n \n @isTest\n static void testInvalidRequestHandling() {\n Test.startTest();\n \n // Prepare invalid request\n RestRequest restRequest = new RestRequest();\n RestResponse restResponse = new RestResponse();\n restRequest.requestBody = Blob.valueOf('invalid json');\n RestContext.request = restRequest;\n RestContext.response = restResponse;\n \n // Call API\n ClassificationResponse response = ClassificationRestAPI.classify();\n \n Test.stopTest();\n \n // Assertions\n System.assert(!response.success, 'Invalid request should fail');\n System.assertEquals(500, RestContext.response.statusCode);\n }\n \n @isTest\n static void testGetClassificationStatus() {\n Test.startTest();\n \n // Create test classification\n Custom_Classification__c classification = TestDataFactory.createClassificationRecord(\n 'SENTIMENT', 'COMPLETED'\n );\n \n // Set up REST context\n RestRequest restRequest = new RestRequest();\n RestResponse restResponse = new RestResponse();\n restRequest.params = new Map<String, String>{\n 'id' => classification.Id\n };\n RestContext.request = restRequest;\n RestContext.response = restResponse;\n \n // Call API\n ClassificationResponse response = ClassificationRestAPI.getClassificationStatus();\n \n Test.stopTest();\n \n // Assertions\n System.assert(response.success, 'Get status should succeed');\n System.assertEquals(200, RestContext.response.statusCode);\n }\n}\n```\n\n## 3. Bulk Classification Testing\n\n### Bulk Classification Service\n\n```apex\n// BulkClassificationService.cls\npublic with sharing class BulkClassificationService {\n \n public static final Integer MAX_BATCH_SIZE = 200;\n public static final Integer DEFAULT_BATCH_SIZE = 50;\n \n public class BulkClassificationRequest {\n public List<ClassificationItem> items;\n public String batchId;\n public Map<String, Object> globalOptions;\n }\n \n public class ClassificationItem {\n public String id;\n public String text;\n public String type;\n public Map<String, Object> options;\n }\n \n @future(callout=true)\n public static void processBulkClassification(String requestJson) {\n try {\n BulkClassificationRequest request = (BulkClassificationRequest) \n JSON.deserialize(requestJson, BulkClassificationRequest.class);\n \n List<Custom_Classification__c> results = new List<Custom_Classification__c>();\n \n for (ClassificationItem item : request.items) {\n Custom_Classification__c result = processIndividualClassification(item);\n result.Batch_Id__c = request.batchId;\n results.add(result);\n }\n \n upsert results External_Id__c;\n \n // Update batch status\n updateBatchStatus(request.batchId, 'COMPLETED');\n \n } catch (Exception e) {\n updateBatchStatus(request.batchId, 'FAILED');\n throw e;\n }\n }\n \n private static Custom_Classification__c processIndividualClassification(\n ClassificationItem item\n ) {\n // Process individual classification logic\n Custom_Classification__c result = new Custom_Classification__c(\n External_Id__c = item.id,\n Input_Text__c = item.text,\n Classification_Type__c = item.type,\n Status__c = 'PROCESSING'\n );\n \n // Simulate classification processing\n result.Confidence_Score__c = Math.random();\n result.Classification_Result__c = 'POSITIVE'; // Mock result\n result.Status__c = 'COMPLETED';\n \n return result;\n }\n \n private static void updateBatchStatus(String batchId, String status) {\n Classification_Batch__c batch = [\n SELECT Id, Status__c \n FROM Classification_Batch__c \n WHERE Batch_Id__c = :batchId \n LIMIT 1\n ];\n batch.Status__c = status;\n batch.Completed_Date__c = System.now();\n update batch;\n }\n}\n```\n\n### Bulk Classification Tests\n\n```apex\n// BulkClassificationTest.cls\n@isTest\nprivate class BulkClassificationTest {\n \n @testSetup\n static void setupBulkTestData() {\n // Create batch record\n Classification_Batch__c batch = new Classification_Batch__c(\n Batch_Id__c = 'TEST_BATCH_001',\n Status__c = 'PENDING',\n Total_Items__c = 100,\n Created_Date__c = System.now()\n );\n insert batch;\n }\n \n @isTest\n static void testBulkClassificationSuccess() {\n Test.startTest();\n \n // Prepare bulk request\n BulkClassificationService.BulkClassificationRequest request = \n new BulkClassificationService.BulkClassificationRequest();\n request.batchId = 'TEST_BATCH_001';\n request.items = new List<BulkClassificationService.ClassificationItem>();\n \n // Create test items\n for (Integer i = 0; i < 10; i++) {\n BulkClassificationService.ClassificationItem item = \n new BulkClassificationService.ClassificationItem();\n item.id = 'ITEM_' + i;\n item.text = 'Test text for classification ' + i;\n item.type = 'SENTIMENT';\n request.items.add(item);\n }\n \n // Process bulk classification\n String requestJson = JSON.serialize(request);\n BulkClassificationService.processBulkClassification(requestJson);\n \n Test.stopTest();\n \n // Verify results\n List<Custom_Classification__c> results = [\n SELECT Id, External_Id__c, Status__c, Batch_Id__c \n FROM Custom_Classification__c \n WHERE Batch_Id__c = 'TEST_BATCH_001'\n ];\n \n System.assertEquals(10, results.size(), 'Should create 10 classification records');\n \n for (Custom_Classification__c result : results) {\n System.assertEquals('COMPLETED', result.Status__c);\n }\n }\n \n @isTest\n static void testBulkClassificationBatchSizeLimit() {\n Test.startTest();\n \n // Test with oversized batch\n BulkClassificationService.BulkClassificationRequest request = \n new BulkClassificationService.BulkClassificationRequest();\n request.batchId = 'TEST_BATCH_LARGE';\n request.items = new List<BulkClassificationService.ClassificationItem>();\n \n // Create items exceeding batch size limit\n for (Integer i = 0; i < BulkClassificationService.MAX_BATCH_SIZE + 10; i++) {\n BulkClassificationService.ClassificationItem item = \n new BulkClassificationService.ClassificationItem();\n item.id = 'LARGE_ITEM_' + i;\n item.text = 'Test text ' + i;\n item.type = 'SENTIMENT';\n request.items.add(item);\n }\n \n Boolean exceptionThrown = false;\n try {\n String requestJson = JSON.serialize(request);\n BulkClassificationService.processBulkClassification(requestJson);\n } catch (Exception e) {\n exceptionThrown = true;\n }\n \n Test.stopTest();\n \n // Should handle large batches appropriately\n System.assert(exceptionThrown || request.items.size() <= BulkClassificationService.MAX_BATCH_SIZE);\n }\n}\n```\n\n## 4. Error Handling Tests\n\n### Error Handling Test Class\n\n```apex\n// ErrorHandlingTest.cls\n@isTest\nprivate class ErrorHandlingTest {\n \n @isTest\n static void testNetworkTimeoutHandling() {\n Test.startTest();\n Test.setMock(HttpCalloutMock.class, new TimeoutMockResponse());\n \n ClassificationRequest request = new ClassificationRequest();\n request.text = 'Test timeout scenario';\n request.type = 'SENTIMENT';\n \n RestRequest restRequest = new RestRequest();\n RestResponse restResponse = new RestResponse();\n restRequest.requestBody = Blob.valueOf(JSON.serialize(request));\n RestContext.request = restRequest;\n RestContext.response = restResponse;\n \n ClassificationResponse response = ClassificationRestAPI.classify();\n \n Test.stopTest();\n \n System.assert(!response.success);\n System.assert(response.message.contains('timeout') || response.message.contains('error'));\n }\n \n @isTest\n static void testInvalidAPIKeyHandling() {\n Test.startTest();\n Test.setMock(HttpCalloutMock.class, new UnauthorizedMockResponse());\n \n ClassificationRequest request = new ClassificationRequest();\n request.text = 'Test unauthorized scenario';\n request.type = 'SENTIMENT';\n \n RestRequest restRequest = new RestRequest();\n RestResponse restResponse = new RestResponse();\n restRequest.requestBody = Blob.valueOf(JSON.serialize(request));\n RestContext.request = restRequest;\n RestContext.response = restResponse;\n \n ClassificationResponse response = ClassificationRestAPI.classify();\n \n Test.stopTest();\n \n System.assert(!response.success);\n System.assertEquals(401, RestContext.response.statusCode);\n }\n \n @isTest\n static void testDatabaseConstraintViolation() {\n Test.startTest();\n \n // Create duplicate records to trigger constraint violation\n Custom_Classification__c record1 = new Custom_Classification__c(\n External_Id__c = 'DUPLICATE_ID',\n Classification_Type__c = 'SENTIMENT'\n );\n insert record1;\n \n Boolean exceptionCaught = false;\n try {\n Custom_Classification__c record2 = new Custom_Classification__c(\n External_Id__c = 'DUPLICATE_ID',\n Classification_Type__c = 'SENTIMENT'\n );\n insert record2;\n } catch (DmlException e) {\n exceptionCaught = true;\n System.assert(e.getMessage().contains('DUPLICATE_VALUE'));\n }\n \n Test.stopTest();\n \n System.assert(exceptionCaught, 'Should catch duplicate value exception');\n }\n}\n\n// Mock classes for error testing\n@isTest\npublic class TimeoutMockResponse implements HttpCalloutMock {\n public HTTPResponse respond(HTTPRequest req) {\n CalloutException ex = new CalloutException();\n ex.setMessage('Read timed out');\n throw ex;\n }\n}\n\n@isTest\npublic class UnauthorizedMockResponse implements HttpCalloutMock {\n public HTTPResponse respond(HTTPRequest req) {\n HttpResponse res = new HttpResponse();\n res.setStatusCode(401);\n res.setBody('Unauthorized');\n return res;\n }\n}\n```\n\n## 5. Rate Limiting Tests\n\n### Rate Limiting Service\n\n```apex\n// RateLimitingService.cls\npublic with sharing class RateLimitingService {\n \n public static final Integer HOURLY_LIMIT = 1000;\n public static final Integer DAILY_LIMIT = 10000;\n \n public static Boolean checkRateLimit(String userId) {\n DateTime now = System.now();\n DateTime hourAgo = now.addHours(-1);\n DateTime dayAgo = now.addDays(-1);\n \n // Check hourly limit\n Integer hourlyCount = [\n SELECT COUNT() \n FROM API_Usage__c \n WHERE User_Id__c = :userId \n AND Request_Time__c >= :hourAgo\n ];\n \n if (hourlyCount >= HOURLY_LIMIT) {\n return false;\n }\n \n // Check daily limit\n Integer dailyCount = [\n SELECT COUNT() \n FROM API_Usage__c \n WHERE User_Id__c = :userId \n AND Request_Time__c >= :dayAgo\n ];\n \n if (dailyCount >= DAILY_LIMIT) {\n return false;\n }\n \n // Record API usage\n recordAPIUsage(userId);\n \n return true;\n }\n \n private static void recordAPIUsage(String userId) {\n API_Usage__c usage = new API_Usage__c(\n User_Id__c = userId,\n Request_Time__c = System.now(),\n Endpoint__c = '/api/v1/classify'\n );\n insert usage;\n }\n \n public static Map<String, Integer> getRateLimitStatus(String userId) {\n DateTime now = System.now();\n DateTime hourAgo = now.addHours(-1);\n DateTime dayAgo = now.addDays(-1);\n \n Integer hourlyUsed = [\n SELECT COUNT() \n FROM API_Usage__c \n WHERE User_Id__c = :userId \n AND Request_Time__c >= :hourAgo\n ];\n \n Integer dailyUsed = [\n SELECT COUNT() \n FROM API_Usage__c \n WHERE User_Id__c = :userId \n AND Request_Time__c >= :dayAgo\n ];\n \n return new Map<String, Integer>{\n 'hourly_used' => hourlyUsed,\n 'hourly_limit' => HOURLY_LIMIT,\n 'hourly_remaining' => HOURLY_LIMIT - hourlyUsed,\n 'daily_used' => dailyUsed,\n 'daily_limit' => DAILY_LIMIT,\n 'daily_remaining' => DAILY_LIMIT - dailyUsed\n };\n }\n}\n```\n\n### Rate Limiting Tests\n\n```apex\n// RateLimitingTest.cls\n@isTest\nprivate class RateLimitingTest {\n \n @testSetup\n static void setupRateLimitData() {\n // Create test user usage records\n String testUserId = UserInfo.getUserId();\n List<API_Usage__c> usageRecords = new List<API_Usage__c>();\n \n DateTime now = System.now();\n \n // Create records approaching hourly limit\n for (Integer i = 0; i < 950; i++) {\n usageRecords.add(new API_Usage__c(\n User_Id__c = testUserId,\n Request_Time__c = now.addMinutes(-i),\n Endpoint__c = '/api/v1/classify'\n ));\n }\n \n insert usageRecords;\n }\n \n @isTest\n static void testRateLimitNotExceeded() {\n Test.startTest();\n \n String testUserId = UserInfo.getUserId();\n Boolean allowed = RateLimitingService.checkRateLimit(testUserId);\n \n Test.stopTest();\n \n System.assert(allowed, 'Request should be allowed when under rate limit');\n }\n \n @isTest\n static void testHourlyRateLimitExceeded() {\n Test.startTest();\n \n String testUserId = UserInfo.getUserId();\n \n // Add more records to exceed hourly limit\n List<API_Usage__c> additionalUsage = new List<API_Usage__c>();\n for (Integer i = 0; i < 60; i++) {\n additionalUsage.add(new API_Usage__c(\n User_Id__c = testUserId,\n Request_Time__c = System.now().addMinutes(-5),\n Endpoint__c = '/api/v1/classify'\n ));\n }\n insert additionalUsage;\n \n Boolean allowed = RateLimitingService.checkRateLimit(testUserId);\n \n Test.stopTest();\n \n System.assert(!allowed, 'Request should be blocked when hourly rate limit exceeded');\n }\n \n @isTest\n static void testRateLimitStatusRetrieval() {\n Test.startTest();\n \n String testUserId = UserInfo.getUserId();\n Map<String, Integer> status = RateLimitingService.getRateLimitStatus(testUserId);\n \n Test.stopTest();\n \n System.assertNotEquals(null, status.get('hourly_used'));\n System.assertNotEquals(null, status.get('daily_used'));\n System.assertEquals(RateLimitingService.HOURLY_LIMIT, status.get('hourly_limit'));\n System.assertEquals(RateLimitingService.DAILY_LIMIT, status.get('daily_limit'));\n }\n \n @isTest\n static void testRateLimitAPIResponse() {\n Test.startTest();\n \n // Simulate rate limit exceeded scenario\n String testUserId = UserInfo.getUserId();\n \n // Fill up to hourly limit\n List<API_Usage__c> maxUsage = new List<API_Usage__c>();\n for (Integer i = 0; i < 60; i++) {\n maxUsage.add(new API_Usage__c(\n User_Id__c = testUserId,\n Request_Time__c = System.now().addMinutes(-1),\n Endpoint__c = '/api/v1/classify'\n ));\n }\n insert maxUsage;\n \n // Try to make API call\n ClassificationRequest request = new ClassificationRequest();\n request.text = 'Test rate limit';\n request.type = 'SENTIMENT';\n \n RestRequest restRequest = new RestRequest();\n RestResponse restResponse = new RestResponse();\n restRequest.requestBody = Blob.valueOf(JSON.serialize(request));\n RestContext.request = restRequest;\n RestContext.response = restResponse;\n \n ClassificationResponse response = ClassificationRestAPI.classify();\n \n Test.stopTest();\n \n System.assert(!response.success, 'Should fail due to rate limit');\n System.assertEquals(429, RestContext.response.statusCode);\n System.assert(response.message.contains('Rate limit exceeded'));\n }\n}\n```\n\n## 6. End-to-End Test Suite\n\n### Comprehensive Integration Test\n\n```apex\n// IntegrationTestSuite.cls\n@isTest\nprivate class IntegrationTestSuite {\n \n @testSetup\n static void setupIntegrationTestData() {\n // Set up comprehensive test data\n Account testAccount = TestDataFactory.createTestAccount('Integration Test Account');\n List<Contact> contacts = TestDataFactory.createTestContacts(20, testAccount.Id);\n \n // Create test classification batch\n Classification_Batch__c batch = new Classification_Batch__c(\n Batch_Id__c = 'INTEGRATION_BATCH_001',\n Status__c = 'PENDING',\n Total_Items__c = 50\n );\n insert batch;\n }\n \n @isTest\n static void testFullWorkflowIntegration() {\n Test.startTest();\n \n // Step 1: Single classification\n ClassificationRequest singleRequest = new ClassificationRequest();\n singleRequest.text = 'This is a positive review of our product';\n singleRequest.type = 'SENTIMENT';\n \n RestRequest restRequest = new RestRequest();\n RestResponse restResponse = new RestResponse();\n restRequest.requestBody = Blob.valueOf(JSON.serialize(singleRequest));\n RestContext.request = restRequest;\n RestContext.response = restResponse;\n \n ClassificationResponse singleResponse = ClassificationRestAPI.classify();\n System.assert(singleResponse.success, 'Single classification should succeed');\n \n // Step 2: Bulk classification\n BulkClassificationService.BulkClassificationRequest bulkRequest = \n new BulkClassificationService.BulkClassificationRequest();\n bulkRequest.batchId = 'INTEGRATION_BATCH_001';\n bulkRequest.items = new List<BulkClassificationService.ClassificationItem>();\n \n for (Integer i = 0; i < 25; i++) {\n BulkClassificationService.ClassificationItem item = \n new BulkClassificationService.ClassificationItem();\n item.id = 'INTEGRATION_ITEM_' + i;\n item.text = 'Integration test text ' + i;\n item.type = 'SENTIMENT';\n bulkRequest.items.add(item);\n }\n \n BulkClassificationService.processBulkClassification(JSON.serialize(bulkRequest));\n \n Test.stopTest();\n \n // Verify bulk processing results\n List<Custom_Classification__c> bulkResults = [\n SELECT Id, Status__c, Confidence_Score__c \n FROM Custom_Classification__c \n WHERE Batch_Id__c = 'INTEGRATION_BATCH_001'\n ];\n \n System.assertEquals(25, bulkResults.size(), 'Should process all bulk items');\n \n // Step 3: Verify rate limiting tracking\n String userId = UserInfo.getUserId();\n Map<String, Integer> rateLimitStatus = RateLimitingService.getRateLimitStatus(userId);\n System.assert(rateLimitStatus.get('hourly_used') > 0, 'Should track API usage');\n }\n \n @isTest\n static void testErrorRecoveryWorkflow() {\n Test.startTest();\n Test.setMock(HttpCalloutMock.class, new PartialFailureMockResponse());\n \n // Test partial failure handling in bulk processing\n BulkClassificationService.BulkClassificationRequest request = \n new BulkClassificationService.BulkClassificationRequest();\n request.batchId = 'ERROR_BATCH_001';\n request.items = new List<BulkClassificationService.ClassificationItem>();\n \n // Add items that will partially fail\n for (Integer i = 0; i < 10; i++) {\n BulkClassificationService.ClassificationItem item = \n new BulkClassificationService.ClassificationItem();\n item.id = 'ERROR_ITEM_' + i;\n item.text = i < 5 ? 'valid text' : 'invalid_trigger_error';\n item.type = 'SENTIMENT';\n request.items.add(item);\n }\n \n try {\n BulkClassificationService.processBulkClassification(JSON.serialize(request));\n } catch (Exception e) {\n // Expected for error testing\n }\n \n Test.stopTest();\n \n // Verify error handling and partial success\n List<Custom_Classification__c> results = [\n SELECT Id, Status__c \n FROM Custom_Classification__c \n WHERE Batch_Id__c = 'ERROR_BATCH_001'\n ];\n \n // Should handle errors gracefully\n System.assert(results.size() >= 0, 'Should handle errors without complete failure');\n }\n}\n\n// Mock for partial failure testing\n@isTest\npublic class PartialFailureMockResponse implements HttpCalloutMock {\n public HTTPResponse respond(HTTPRequest req) {\n HttpResponse res = new HttpResponse();\n if (req.getBody().contains('invalid_trigger_error')) {\n res.setStatusCode(400);\n res.setBody('{\"error\": \"Invalid input\"}');\n } else {\n res.setStatusCode(200);\n res.setBody('{\"success\": true, \"classification\": \"positive\"}');\n }\n return res;\n }\n}\n```\n\n## 7. Performance and Load Testing\n\n### Performance Test Class\n\n```apex\n// PerformanceTest.cls\n@isTest\nprivate class PerformanceTest {\n \n @isTest\n static void testHighVolumeClassification() {\n Test.startTest();\n \n // Test processing time for large batches\n List<String> testTexts = new List<String>();\n for (Integer i = 0; i < 200; i++) {\n testTexts.add('Performance test text sample number ' + i + \n '. This is a longer text to simulate real-world usage scenarios.');\n }\n \n Long startTime = System.currentTimeMillis();\n \n // Process classifications\n List<Custom_Classification__c> results = new List<Custom_Classification__c>();\n for (String text : testTexts) {\n Custom_Classification__c result = new Custom_Classification__c(\n Input_Text__c = text,\n Classification_Type__c = 'SENTIMENT',\n Status__c = 'COMPLETED',\n Processing_Date__c = System.now()\n );\n results.add(result);\n }\n \n insert results;\n \n Long endTime = System.currentTimeMillis();\n Long processingTime = endTime - startTime;\n \n Test.stopTest();\n \n // Performance assertions\n System.assertEquals(200, results.size(), 'Should process all items');\n System.assert(processingTime < 10000, 'Processing should complete within 10 seconds');\n \n // Verify CPU usage stays within limits\n System.assert(Limits.getCpuTime() < Limits.getLimitCpuTime() * 0.8, \n 'CPU usage should stay under 80%');\n }\n \n @isTest\n static void testConcurrentAPIRequests() {\n Test.startTest();\n \n // Simulate concurrent requests\n List<ClassificationResponse> responses = new List<ClassificationResponse>();\n \n for (Integer i = 0; i < 5; i++) {\n ClassificationRequest request = new ClassificationRequest();\n request.text = 'Concurrent test ' + i;\n request.type = 'SENTIMENT';\n \n RestRequest restRequest = new RestRequest();\n RestResponse restResponse = new RestResponse();\n restRequest.requestBody = Blob.valueOf(JSON.serialize(request));\n RestContext.request = restRequest;\n RestContext.response = restResponse;\n \n ClassificationResponse response = ClassificationRestAPI.classify();\n responses.add(response);\n }\n \n Test.stopTest();\n \n // Verify all requests succeeded\n for (ClassificationResponse response : responses) {\n System.assert(response.success, 'Concurrent requests should all succeed');\n }\n }\n}\n```\n\n## 8. Test Execution and Monitoring\n\n### Test Runner Utility\n\n```apex\n// TestRunner.cls\npublic class TestRunner {\n \n public static void runAllIntegrationTests() {\n // Run specific test classes in order\n List<String> testClasses = new List<String>{\n 'ClassificationAPITest',\n 'BulkClassificationTest',\n 'ErrorHandlingTest',\n 'RateLimitingTest',\n 'IntegrationTestSuite',\n 'PerformanceTest'\n };\n \n for (String testClass : testClasses) {\n System.debug('Running test class: ' + testClass);\n Test.runTests(new List<String>{testClass});\n }\n }\n \n public static void generateTestReport() {\n // Query test results\n List<ApexTestResult> results = [\n SELECT Id, MethodName, Outcome, Message, StackTrace\n FROM ApexTestResult\n WHERE AsyncApexJobId IN (\n SELECT Id FROM AsyncApexJob \n WHERE JobType = 'TestRequest'\n AND CompletedDate = TODAY\n )\n ORDER BY CompletedDate DESC\n ];\n \n // Generate report\n Integer passed = 0;\n Integer failed = 0;\n List<String> failures = new List<String>();\n \n for (ApexTestResult result : results) {\n if (result.Outcome == 'Pass') {\n passed++;\n } else {\n failed++;\n failures.add(result.MethodName + ': ' + result.Message);\n }\n }\n \n System.debug('=== INTEGRATION TEST REPORT ===');\n System.debug('Total Tests: ' + results.size());\n System.debug('Passed: ' + passed);\n System.debug('Failed: ' + failed);\n System.debug('Success Rate: ' + ((Decimal)passed / results.size() * 100).setScale(2) + '%');\n \n if (!failures.isEmpty()) {\n System.debug('=== FAILURES ===');\n for (String failure : failures) {\n System.debug(failure);\n }\n }\n }\n}\n```\n\n## 9. Deployment Validation\n\n### Package Validation Script\n\n```bash\n#!/bin/bash\n# deploy_validation.sh\n\necho \"Starting Salesforce ISV Package Validation...\"\n\n# Set variables\nSANDBOX_USERNAME=\"your-sandbox@example.com\"\nPACKAGE_VERSION=\"1.0.0\"\n\n# Deploy to sandbox\necho \"Deploying to sandbox...\"\nsf project deploy start --target-org $SANDBOX_USERNAME --dry-run\n\n# Run tests\necho \"Running integration tests...\"\nsf apex run test --target-org $SANDBOX_USERNAME --test-suite \"IntegrationTestSuite\" --result-format human --coverage-format text\n\n# Validate package\necho \"Validating package...\"\nsf package version promote --package \"$PACKAGE_VERSION\" --target-dev-hub $SANDBOX_USERNAME\n\necho \"Validation complete!\"\n```\n\nThis comprehensive integration testing framework provides:\n\n1. **Complete API endpoint testing** with success and error scenarios\n2. **Bulk processing validation** with size limits and error handling\n3. **Rate limiting enforcement** and monitoring\n4. **Error handling** for network, authentication, and data issues\n5. **Performance testing** for high-volume scenarios\n6. **End-to-end workflow validation**\n7. **Test reporting and monitoring utilities**\n\nThe tests are designed to run in Salesforce sandbox environments and validate all aspects of your ISV package before production deployment."
}Audit Trail (2)
1d agotask_completedTerminal Lu
1d agotask_claimedTerminal Lu
Task ID: ee18b6f7-e018-44a1-ae19-b3aa8a08949f