|
| 1 | +# Example: Test Generation for Moment.js Function |
| 2 | + |
| 3 | +This example demonstrates the process of generating tests for the **`moment().add`** function in Moment.js using a custom test generation framework. |
| 4 | + |
| 5 | +## **Importing Dependencies** |
| 6 | + |
| 7 | +```typescript |
| 8 | +import path from "path"; |
| 9 | +import { |
| 10 | + APIFunction, |
| 11 | + FunctionDescriptor, |
| 12 | + Codex, |
| 13 | + TestGenerator, |
| 14 | + MochaValidator, |
| 15 | + BaseTestResultCollector, |
| 16 | +} from "./"; |
| 17 | +``` |
| 18 | + |
| 19 | +Imports necessary libraries and modules, including the test generation and validation classes. |
| 20 | + |
| 21 | +## **Defining the Function Descriptor** |
| 22 | + |
| 23 | +```typescript |
| 24 | +const functionDescriptor: FunctionDescriptor = { |
| 25 | + type: "function", |
| 26 | + signature: "(amount: number, unit: string)", |
| 27 | + isAsync: false, |
| 28 | + implementation: ` |
| 29 | + // Pseudo-implementation for moment().add |
| 30 | + `, |
| 31 | + isConstructor: false, |
| 32 | + docComment: |
| 33 | + "Adds the specified amount of time to the moment object. The unit can be years, months, weeks, days, hours, minutes, seconds, or milliseconds. This function modifies the original moment object and returns it for chaining.", |
| 34 | +}; |
| 35 | +``` |
| 36 | + |
| 37 | +Describes the function being tested, including its signature and a brief documentation. |
| 38 | + |
| 39 | +## **Initializing the Test Generator Components** |
| 40 | + |
| 41 | +```typescript |
| 42 | +const apiFunction = new APIFunction("moment().add", functionDescriptor, "moment"); |
| 43 | +const model = new Codex(false, { |
| 44 | + n: 5, |
| 45 | + max_tokens: 150, |
| 46 | + temperature: 0.7, |
| 47 | +}); |
| 48 | +const momentPath = path.join(require.resolve("moment"), "../"); |
| 49 | +const validator = new MochaValidator("moment", momentPath); |
| 50 | +const collector = new BaseTestResultCollector(); |
| 51 | +const temperatures = [0.7]; |
| 52 | +const snippetMap = new Map([ |
| 53 | + [apiFunction.functionName, ["moment().add(10, 'days')", "moment().add(1, 'year').format('YYYY')"]], |
| 54 | +]); |
| 55 | +const generator = new TestGenerator(temperatures, (fn) => snippetMap.get(fn), model, validator, collector); |
| 56 | +``` |
| 57 | + |
| 58 | +Initializes the object that makes prompts to the Codex-based completion API, and sets up paths and validators for test generation. Used `https://api.openai.com/v1/engines/gpt-3.5-turbo-instruct/completions`. |
| 59 | + |
| 60 | +## **Test Generation and Collection** |
| 61 | + |
| 62 | +```tsx |
| 63 | +console.log("Generating test for moment().format()"); |
| 64 | +await generator.generateAndValidateTests(apiFunction); |
| 65 | +const testInfos = collector.getTestInfos(); |
| 66 | +console.log("Test generation complete. Test Details:"); |
| 67 | +testInfos.forEach((test) => { |
| 68 | + console.log(`Test ID: ${test.id}, Test Name: ${test.testName}, Outcome: ${test.outcome.status}`); |
| 69 | +}); |
| 70 | + |
| 71 | +``` |
| 72 | + |
| 73 | +Generates tests and logs the results to the console. |
| 74 | + |
| 75 | +## **Note on Test File Management** |
| 76 | + |
| 77 | +By default, the test files are temporarily stored in the **`node_modules/<library>/`** directory and are erased after testing. To change this behavior and save the test files, you can implement custom versions of the **`MochaValidator`** to a file saving version as shown below: |
| 78 | + |
| 79 | +```typescript |
| 80 | +class CustomMochaValidator extends MochaValidator { |
| 81 | + constructor(packageName, packagePath, testDirectory) { |
| 82 | + super(packageName, packagePath); |
| 83 | + this.testDirectory = testDirectory; // Custom directory for saving test files |
| 84 | + // Ensure the directory exists |
| 85 | + if (!fs.existsSync(this.testDirectory)) { |
| 86 | + fs.mkdirSync(this.testDirectory, { recursive: true }); |
| 87 | + } |
| 88 | + } |
| 89 | + |
| 90 | + validateTest(testName, testSource) { |
| 91 | + let testFile = path.join(this.testDirectory, testName + '.js'); |
| 92 | + fs.writeFileSync(testFile, testSource); |
| 93 | + console.log(`Test saved to: ${testFile}`); // Log where the test is saved |
| 94 | + // Call original validateTest logic here if needed, or simulate a test outcome |
| 95 | + return { status: 'PASSED' }; // Simulate a passed test outcome |
| 96 | + } |
| 97 | + |
| 98 | + // Override the cleanup to prevent deletion |
| 99 | + cleanup() { |
| 100 | + console.log('Cleanup skipped, tests preserved.'); |
| 101 | + } |
| 102 | +} |
| 103 | +``` |
| 104 | + |
| 105 | +> OBS: The `CustomMochaValidator` implementation above is just an idea. It was not tested, unlike the code before. |
| 106 | +
|
| 107 | +## Running the script |
| 108 | + |
| 109 | +The code shown in this example is at `/examples/testGenerationScript.ts`, but it will not run by default. To run the test generation script follow the below steps: |
| 110 | + |
| 111 | +1. Copy `testGenerationScript.ts` to `src/`, making sure that the second import directory is `./` |
| 112 | + |
| 113 | + ```sh |
| 114 | + cp examples/testGenerationScript.ts src/ |
| 115 | + ``` |
| 116 | + |
| 117 | +2. Install Moment.js with `npm` |
| 118 | + |
| 119 | + ```sh |
| 120 | + npm install moment |
| 121 | + ``` |
| 122 | + |
| 123 | +3. Build the files again |
| 124 | + |
| 125 | + ```sh |
| 126 | + npm run build |
| 127 | + ``` |
| 128 | + |
| 129 | +4. Finally, set the environment variables and run the script with `node`: |
| 130 | + |
| 131 | + ```sh |
| 132 | + export TESTPILOT_LLM_API_ENDPOINT='https://api.openai.com/v1/engines/gpt-3.5-turbo-instruct/completions' |
| 133 | + export TESTPILOT_LLM_AUTH_HEADERS='{"Authorization": "Bearer <your API key>", "OpenAI-Organization": "<your organization ID>"}' |
| 134 | + node dist/testGenerationScript.js |
| 135 | + ``` |
0 commit comments