There are a number of different patterns we can use to automate CRUD testing. At the very minimum, we want to test one operation of each: Create, Read, Update, and Delete. For the purposes of this discussion, let’s assume the following:
1. We are testing the simple form used in this post
2. We are doing UI automation (API automation will be discussed in a future post)
This is the pattern I like to use when testing CRUD. I’m writing in Specflow/Cucumber for simplicity:
Scenario: Adding a user
Given I am adding a new user
When I add a first name and save
Then I navigate to the Users page
And I verify that the first name is present
Scenario: Updating a user
Given I am updating a user
When I change the first name and save
Then I navigate to the User page
And I verify that the first name has been updated
Scenario: Deleting a user
Given I am deleting a user
When I delete the first name and save
Then I navigate to the Users page
And I verify that the first name is not present
These three tests have tested Create, Update, and Delete. The first two tests are also testing Read, because we are retrieving the user for our assertions. Therefore, with these three tests I’m testing the basic functionality of CRUD.
Some may argue that these tests are not idempotent. Idempotency means that a test can be run again and again with the same results. I can’t run the third test over and over again with the same results, for example, because after the first time I run it, the user is no longer there to delete.
If we wanted to solve the idempotency issue, we could write a test like this:
Scenario: CRUD testing of user
Given I am testing CRUD
When I add a first name and save
And I verify that the first name is present
When I change the first name and save
And I verify that the first name has been updated
When I delete the first name and save
Then I verify that the first name has been deleted
This one scenario tests all the CRUD functionality of the form. But it also has three different assertions. I prefer to keep my UI tests down to one or two assertions.
When my original three scenarios are looked at as a group, they are idempotent together. My tests are responsible for creating and deleting my data.
It would also be a good idea to test some negative scenarios with our CRUD testing, such as creating a user with an invalid first name, and updating a user with an invalid first name. These tests could look like this:
Scenario: Creating a user with an invalid first name
Given I am adding a new user
When I enter an invalid first name and save
Then I verify that I receive the appropriate error message on the page
And I navigate to the User page
And I verify that the user has not been added
Scenario: Updating a user with an invalid first name
Given I am updating an existing user
When I update the first name with an invalid value and save
Then I verify that I receive the appropriate error message on the page
And I navigate to the User page
And I verify that the existing first name has not been updated
The first scenario is idempotent, because nothing is actually being added to the database. The second scenario is also idempotent, but it requires an existing user. We could assume that our user will always be present in the database, but if someone inadvertently deletes it, our test will fail. In this case, it would be good to add in a Before step and an After step that will create the user at the beginning of the test suite and delete it when the suite is over.
These five scenarios- the three to test the happy path, and the two negative tests- would be a great regression suite for our simple form. This is a very simple form, with just one field, which is not exactly a real-world scenario. But it is a good way to start thinking about automated UI test patterns.