I'm new to a project that is in active development but is a mature application. It has a lot of Protractor/Jasmine tests, but they are organized somewhat poorly. For example, multiple identical or nearly identical spec files, but one is smoke.ts and the other is regression.ts. I'm used to using Cucumber, which makes it more obvious what user stories are covered by testing. But Jasmine makes it less obvious (plus they were written poorly). As I'm learning the application, I want to know what pieces of functionality are covered by testing and I am wondering how you would approach this situation. There is a user handbook that is helpful, but dense, and not exactly what I'm looking for. I'm thinking: user story maps created and then triangulated with the automated test cases. And maybe before that an attempt to put Given-When-Then in some of the test cases, even if it's just commented to start.
-
Welcome. Can you give an example of one of your test cases? What makes it poorly written? What makes it less obvious of what is being tested?– Lee JensenCommented Apr 27, 2021 at 17:47
-
An exacmple would be, in the 'describe' block, the text is somewhat unspecific. Like, 'user: profile administration.' From a test automation perspective, a lot of work is happening in describe blocks that should happen in the page object. So, the 'describe' text is not helpful, and the methods are stacked/poorly named as well (urgh) which makes it very hard to see quickly what is being tested.– Andy J.Commented Apr 27, 2021 at 21:18
-
What type of coverage is important for the people who will be using this information? Coverage measured from automated checks is limited to the type of documentation you have, e.g. lines of code or specific scenarios written in Gherkin. Do you need deeper information? Refer this answer for other types of coverage your automated checks may not be able to assess: sqa.stackexchange.com/a/44995/12740– João FariasCommented Apr 28, 2021 at 7:18
-
@AndyJ. Your comments help give some more information. Would it be possible for you to paste an entire spec file or a full describe? That way, we can see what " a lot of work happening in describe blocks should happen page objects" looks like.– Lee JensenCommented Apr 28, 2021 at 14:00
1 Answer
First, I think this question is less about code coverage -- "a measure used to describe the degree to which the source code of a program is executed when a particular test suite runs" -- and more about how to understand and possibly refactor a testing framework created by someone else.
By definition, code coverage is usually represented by numbers like: a percentage value, number of lines tested, number of functions/classes tested. Code coverage in this sense is easier to determine with tools for unit testing. Calculating code coverage like this for UI tests are typically harder.
Assumptions I'm making for the example:
- Tests/specs are in JavaScript due to using Jasmine and Protractor
- Tests are UI tests
- Tests use the Page Object Model
One approach is to have a clear directory structure to how the code is setup. As an example, you can do something like:
./
|
|__/config
|__/data
|__/pages
|____page1 (ex: login.page.js)
|____page2 (ex: header.page.js)
|
|__/tests
|____spec1 (ex: login.spec.js or login.positive.spec.js)
|____spec2 (ex: login.negative.spec.js)
Note: while I'm listing the pages and specs as single files, you can certainly have folders under /pages or /tests to keep it organized depending on how many tests you have. I tend to recommend that the /tests directory follow a similar directory structure as the /pages directory, that way, it's easy to see the relationship.
As for writing the describes themselves, one option is to use a User Story approach.
describe('As a user, I want to...', () =>
{
beforeAll(() =>
{
browser.url('https://example.com');
});
it('Login to website', () =>
{
const loginPage = new LoginPage(browser);
// some criteria to assert you're on the login page
expect(browser.getTitle()).toEqual('Example');
expect(browser.getUrl()).toContain('/signin');
loginPage.login('username', 'password');
// some criteria you've logged in successfully
expect(browser.getTitle()).toEqual('I'm Logged In');
expect(browser.getUrl()).toContain('/landing');
});
it('Logout of website', () =>
{
const header= new Header(browser);
header.clickLogout();
// some criteria you've logged out successfully
expect(browser.getTitle()).toEqual('Example');
expect(browser.getUrl()).toContain('/signin');
});
});