Testing
Why?
Ensures things work
Breaks functionality down to "testable chunks"
Catches breaks in the future
How
In python - UnitTest
In Javascript - Jest
For both - Cypress
How to organize tests
Start with the goal in mind
often easier to write test names upfront
Creating test suites for groupings
Think of this as an outline
Start as high level as possible
Text
Login works
A user can send a message
Higher level tests are more useful since they cover more
EG
Test happy path first, and start at the end
Test login returns 200 response
Test form fails to validate with missing email
Test "success" string is contained in html
Text
Create Actual Result
actual = make_test_request.status
actual = model_Im_saving.objects.count()
How to structure a test
Test writing is MECHANICAL
Create Sample Data
In Django, this is through Model-Baker
In Javascript, this is through Mirage.js
This sample data is SPECIFIC to your test. As specific as you need. Opportunities for reuse will be obvious and occur as more writing happens
Create expected result
Often really simple:
expected = 200 # server response
expected = "this is a success string" # happy string
expected = 0 # result of a count
Kick off smallest unit to create tested effect
Higher level tests kick off higher level flows
Most often a web request
Compare expected and actual
That's it. That's the test
class UserAdminTest(TestCase):
def setUp(self):
form_data = self.login_form_data = {
"username": "ben@coolguy.com",
"password": "yeahman",
}
self.user = baker.make_recipe(
"hle.account.user",
email=form_data["username"],
is_superuser=True,
is_staff=True,
password=make_password(form_data["password"]),
)
self.client.login(
username=self.login_form_data["username"],
password=self.login_form_data["password"],
)
def test_user_admin_list(self):
url = reverse("admin:account_user_changelist")
response = self.client.get(url)
actual = response.status_code
expected = 200
self.assertEqual(actual, expected)
Integration Testing
Integration testing pretends to be a user on a web page
Using scripted browser actions
Slow, so don't run by default
./manage.py test --tag=integration
How to create an integration test
PM uses the website to complete task, while using a recorder plugin
https://github.com/KabaLabs/Cypress-Recorder
cy.visit('/login?next=/account');
cy.get('[data-cy=login-email]')
.click()
.type('ben@lightmatter.com')
.get('[data-cy=login-password]')
.type('asdfasdf')
.get('[data-cy=submit-login]')
.click();
cy.location().should(location => {
expect(location.pathname).to.eq('/account');
});
PM Sends record to programmer
Programmer replaces sample data with precreated data
describe('Login page', () => {
it('a user follows next login with the form', () => {
cy.visit('/login?next=/account');
cy.get('[data-cy=login-email]')
.click()
.type('jonnyrico@fednet.gov')
.get('[data-cy=login-password]')
.type('iwanttoknowmore')
.get('[data-cy=submit-login]')
.click();
cy.location().should(location => {
expect(location.pathname).to.eq('/account');
});
cy.get('#client-snackbar').should('contain', 'Successfully logged in');
});
});
class RegistrationCypressTest(NextjsCypressTest):
def test_login(self):
self.user = baker.make_recipe(
User,
email="jonnyrico@fednet.gov",
password=make_password("iwanttoknowmore"),
)
result = self.run_cypress_test("login.js", silent=True, browser=False)
self.assertEqual(result.returncode, 0)
Works by running a node server in a side process of django webapp
Javascript Snapshoting
Every render is saved and compared on file change.
Coverage testing
Useful to know you're doing it
Not by itself a guarantee tests are working
Testing
By Ben Beecher
Testing
- 760