You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
| No comment | Enables automatic transactions (default) |
318
+
| No comment | Enables automatic transactions (default) |
319
+
320
+
## Trigger Control During Tests
321
+
322
+
The framework automatically disables database triggers during test execution to ensure true unit test isolation. This prevents external dependencies and side effects from interfering with tests.
323
+
324
+
### How It Works
325
+
326
+
When tests run (either via `tool4d` or from a host project), the framework sets a flag in 4D's shared `Storage`:
327
+
328
+
```4d
329
+
Storage.triggersDisabled.testMode = True
330
+
```
331
+
332
+
This flag remains set for the duration of the test run, allowing triggers in the host project to check and skip execution during testing.
333
+
334
+
### Running Tests from a Host Project
335
+
336
+
When running tests from a host project (not standalone), you **must** pass the host project's Storage object to enable trigger control:
337
+
338
+
```4d
339
+
// In your host project's method to run tests
340
+
var $testStorage : Object
341
+
$testStorage:=Storage // Pass the host project's Storage
342
+
343
+
// Call the testing component method with both cs and Storage
344
+
Testing_RunTestsWithCs(cs; $testStorage)
345
+
```
346
+
347
+
**Important:** Components have separate Storage objects from their host projects. By passing the host's Storage, the test framework can set flags that your host project's triggers can check.
348
+
349
+
### Implementing Trigger Control in Host Projects
350
+
351
+
To make triggers skip execution during tests, add this check at the beginning of each trigger:
352
+
353
+
```4d
354
+
// At the start of your trigger code
355
+
If (Storage.triggersDisabled#Null) && (Storage.triggersDisabled.testMode=True)
356
+
return // Skip trigger execution during tests
357
+
End if
358
+
359
+
// Normal trigger logic continues here...
360
+
```
361
+
362
+
### Example: Complete Trigger Implementation
363
+
364
+
```4d
365
+
// Table trigger with test mode support
366
+
If (Storage.triggersDisabled#Null) && (Storage.triggersDisabled.testMode=True)
367
+
return
368
+
End if
369
+
370
+
// Normal trigger logic
371
+
Case of
372
+
: (Trigger event=On Saving New Record Event)
373
+
// Validate and set default values
374
+
If ([MyTable]requiredField="")
375
+
[MyTable]requiredField:="DefaultValue"
376
+
End if
377
+
378
+
: (Trigger event=On Saving Existing Record Event)
379
+
// Update modification timestamp
380
+
[MyTable]modifiedAt:=Current date
381
+
End case
382
+
```
383
+
384
+
### Benefits of Trigger Control
385
+
386
+
-**True Unit Testing**: Tests can focus on business logic without trigger side effects
387
+
-**Faster Tests**: Skipping triggers reduces test execution time
388
+
-**Test Isolation**: Each test runs in a clean state without trigger interference
389
+
-**Flexibility**: Easily enable triggers for integration tests when needed
390
+
391
+
### Configuring Trigger Behavior
392
+
393
+
The framework provides flexible control over when triggers execute:
394
+
395
+
#### Global Trigger Control via User Parameters
396
+
397
+
Control the default trigger behavior for all tests using the `triggers` parameter:
398
+
399
+
```bash
400
+
# Enable triggers for all tests (default is disabled)
401
+
make test triggers=enabled
402
+
403
+
# Explicitly disable triggers (default behavior)
404
+
make test triggers=disabled
405
+
406
+
# With other parameters
407
+
make test format=json triggers=enabled tags=integration
408
+
```
409
+
410
+
**Default Behavior**: Triggers are **disabled by default** (`triggers=disabled`) to ensure true unit test isolation.
411
+
412
+
#### Per-Test Trigger Control via Comments
413
+
414
+
Individual tests can override the global setting using comment annotations:
415
+
416
+
```4d
417
+
// #triggers: enabled
418
+
Function test_withTriggersEnabled($t : cs.Testing)
419
+
// This test will have triggers enabled regardless of global setting
420
+
// Useful for integration tests that need to verify trigger behavior
421
+
422
+
// #triggers: disabled
423
+
Function test_withTriggersDisabled($t : cs.Testing)
424
+
// This test will have triggers disabled regardless of global setting
425
+
// Useful for unit tests that need isolation
426
+
427
+
Function test_defaultBehavior($t : cs.Testing)
428
+
// No annotation - uses global setting from triggers parameter
429
+
```
430
+
431
+
#### Use Cases
432
+
433
+
**Unit Tests (triggers disabled):**
434
+
```4d
435
+
// #triggers: disabled
436
+
Function test_calculateTotal($t : cs.Testing)
437
+
// Test business logic without trigger side effects
438
+
// Default behavior - no annotation needed
439
+
```
440
+
441
+
**Integration Tests (triggers enabled):**
442
+
```4d
443
+
// #tags: integration
444
+
// #triggers: enabled
445
+
Function test_orderProcessingWithTriggers($t : cs.Testing)
446
+
// Test complete flow including trigger execution
447
+
```
448
+
449
+
**Hybrid Approach:**
450
+
```bash
451
+
# Run unit tests with triggers disabled (default)
452
+
make test-unit
453
+
454
+
# Run integration tests with triggers enabled
455
+
make test-integration triggers=enabled
456
+
```
457
+
458
+
### When to Allow Triggers
459
+
460
+
For integration tests that specifically need to test trigger behavior:
461
+
462
+
1.**Use per-test annotations** with `// #triggers: enabled`
463
+
2.**Enable globally** with `triggers=enabled` parameter for integration test suites
464
+
3.**Tag appropriately** using `// #tags: integration` for filtering
465
+
4.**Test trigger logic directly** by extracting it into testable functions
466
+
5.**Mock trigger behavior** in unit tests using test doubles
467
+
468
+
### Implementation Notes
469
+
470
+
- The `Storage.triggersDisabled.testMode` flag is automatically managed by the test framework
471
+
- Per-test trigger control automatically restores the default behavior after each test
472
+
- No manual cleanup is required - flags persist only for the test process lifetime
473
+
- Works in both interpreted and compiled modes
474
+
- Compatible with parallel test execution - each worker process has its own Storage state
475
+
- Test-level annotations take precedence over global `triggers` parameter
0 commit comments