Vanilla has numerous testing utilities to make automated testing easier.
A test will automatically be run in CI if it meets the following conditions.
- The filename matches the following pattern:
*Test.php
. - The classname matches the filename.
- The class extends in some way
\PHPUnit\Framework\TestCase
.
Base Classes
Vanilla has a few recommended test cases to extend and offer setup utilities.
VanillaTestCase
Offers various additional assertions on top of the base PHPUnit TestCase
. Very fast setup, but no database, routing, or container setup is provided.
BootstrapTestCase
Provides a full bootstrapping of Vanilla. Usually, you'll want to use this test case instead of the MinimalContainerTestCase
since it more faithfully recreate's Vanilla's bootstrap.
SiteTestCase
If you subclass this test case then you'll get a full site install that you can test against. The site installed once for the class so make sure each test within the class work against the same install.
You can control the addons that are enabled with the install by overriding the getAddons()
method.
AbstractApiV2Test
Sets up a "production-like" test harness, with full routing, database access, and utilities for starting sessions and calling APIv2 endpoints. Generally, you can usually use the SiteTestCase
instead of this one.
AbstractResourceTest
Extend this to provide numerous default test assertions on an API endpoint. This test case expects a fully formed CRUD API conforming to vanilla norms. EG. POST, PATCH, GET, GET edit, DELETE, INDEX must all be defined. There are a few properties to configure.
Example
public static $addons = ['vanilla', 'subcommunities'];
protected $baseUrl = '/subcommunities';
protected $resourceName = 'subcommunity';
protected $patchFields = ['name', 'folder', 'locale', 'categoryID', 'productID', 'isDefault', 'sort'];
protected $testPagingOnIndex = false;
protected $pk = 'subcommunityID';
Common Traits
Vanilla provides various traits to make testing easier.
BootstrapTrait
Used to bootstrap a Garden\Container
instance with some good defaults. The container can be accessed with self::container()
in order to insatiate classes that require dependency injection.
Notably this is used in BootstrapTestCase
.
SiteTestTrait
Use this trait if you want the site installed, but cant extend the SitetestCase
class. This trait is used for tests that require starting addons. This is based on BootstrapTrait
but adds on top the following utilities:
- Enable addons by overriding the
getAddons()
method. - Get an
HttpClient
instance for making calls to APIv2 with $this->api()
. - Get something like an
HttpClient
for making calls to legacy controllers (Gdn_Controllers
) with $this->bessy()
. - Tests will run on an "installed" site with default configuration values applied.
Testing Events
Creating Content for Tests
Testing Gdn_Controllers
To test a Gdn_Controller, extends AbstractAPIv2Test
. You can use the various API traits above as well as other calls to create your data.
Then you use bessy() in order to make assertions about pages.
Testing Data Example
/**
* Editing a discussion should fill its form values.
*/
public function testGetCommentEdit(): void {
\Gdn::session()->start($this->moderatorID);
/** @var \PostController $r */
$r = $this->bessy()->get(
'/post/edit-comment',
['commentID' => $this->comment['CommentID']]
);
$this->assertEquals($this->comment['DiscussionID'], $r->Form->getValue('DiscussionID'));
$this->assertSame($this->comment['Body'], $r->Form->getValue('Body'));
}
Testing HTML example
/**
* Test run the test
*/
public function testGroupPage() {
$this->createGroup(['name' => 'My Group']);
$event1 = $this->createEvent();
$event2 = $this->createEvent([
'name' => 'My Event <script>alert("Hello")</script>',
]);
$html2 = $this->bessy()->getHtml("/group/{$this->lastInsertedGroupID}-my-group");
$html2->assertCssSelectorText('.Event:nth-of-type(2) .Title a', 'My Event <script>alert("Hello")</script>');
}
Other Notable Utilities
Mocking Dates & Times
$mockedDataTime = CurrentTimeStamp::mockTime('Dec 24 2020');
$mockedDataTime = CurrentTimeStamp::mockTime(12124124);
$mockedDataTime = CurrentTimeStamp::mockTime(new DateTime());
Wiping a database table
BootstrapTrait::resetTable('Discussion')