Here is the shape of a basic Apex test class. Create it in a sandbox or scratch org, point it at the class or trigger you want to cover, and run it before you deploy. The same structure scales from a single unit test to a full suite.
- Create the class with @isTest
In the Developer Console or VS Code, create a new Apex class. Add the @isTest annotation above the class declaration and declare it private, since a pure test class does not need to be called from anywhere else.
- Build test data
Inside a @testSetup method or at the top of the test method, insert the records your code needs. Create them in the test rather than relying on existing org data, and insert a list of around 200 records when you want to confirm bulk behavior.
- Run the code inside startTest and stopTest
Call Test.startTest(), then invoke the method or trigger you are testing, then call Test.stopTest(). This gives your code a fresh set of governor limits and forces any queued asynchronous work to finish before you check results.
- Assert the outcomes
After stopTest(), query the records back and use Assert or System.assertEquals to confirm the values are what you expect. Cover both a valid case and an invalid one so the failure path is tested too.
- Run and check coverage
Execute the test from the Apex Test Execution page or the Developer Console. Confirm it passes and review the coverage it produced, aiming well above the 75% minimum before you deploy.
Placed above the class declaration to mark it as a test class so its code is excluded from the Apex character limit.
At least one method marked @isTest (or the legacy testMethod keyword) that contains the actual test logic.
Records created inside the test, since SeeAllData is false by default and the test cannot see existing org data.
Assert or System.assertEquals calls that verify the results, without which the test only adds coverage and checks nothing.
- Coverage without assertions passes even when the code is broken. Always verify outcomes, not just that lines ran.
- Hardcoded record IDs fail in other orgs. Create records in the test and read their IDs back instead.
- Asynchronous work stays queued unless Test.stopTest() runs, so assertions placed before it will check nothing.
- Real HTTP callouts are blocked in tests. Register a mock with Test.setMock() or the test throws an exception.
- Setting SeeAllData=true makes the test depend on org records that may differ between environments, so avoid it.