Stop using Selenium so much, stupid!
Selenium is really great tool which can help you to speed up testing process and decrease time needed for checking new releases. But do we really use it as we should?
Let’s look at “standard” selenium test flow. You don’t do it that way? Good for you!
PS: This test case is very high level, it is just for an example.
Scenario: Check if logged in user can apply on a job offer
Open Homepage
Click Login
Fill User field
Fill Password field
Click Login
Fill Search field
Click Search
Click Job Offer name on list of results
Click apply button
Fill the apply form
Confirm Apply
What it’s done here, it’s one of the paths real user can follow. It’s correct from business perspective, it mimics real user's behavior and it’s one of the worst possible way of using Selenium.
Why? I see two main issues here.
Don’t test more than you must!
Your job in this scenario is not to test whole user flow but apply functionality for logged in user. No less, no more. If you want to make sure login process works fine, write test(s) for login process and don’t let Selenium touch login button ever again.
What? But I must be logged in to check apply process! Yes, you do, so login in simplest and fastest possible way. Exact mechanism will depend on your application – use API, developer mode, whatever you can. Just don’t fill login and password fields.
Example of login by API (Java, RestAssured):
public static Map<String, String> logIn(String login, String password) {
Utils.setRestApiBaseUri(TestRunEnvironment.getBaseUri();
Utils.setRestApiBasePath("/index.php");
Response
response =
given()
.param("event", "login.doLogin")
.formParam("loginUserLogin", login)
.formParam("loginUserPassword", password)
.formParam("rememberme", "true")
.cookie("language", "EN")
.expect().statusCode(202)
.when()
.post();
Map<String, String> cookies = response.getCookies();
//rewrite all cookies into webdriver
for (Map.Entry<String, String> cookie : cookies.entrySet()) {
TestManager.getTest().getWebDriver().manage()
.addCookie(new org.openqa.selenium.Cookie(cookie.getKey(), cookie.getValue()));
}
Every single action that you don’t really need to perform but you need results of it, can be performed in similar way (at least should be, if your application is testable).
So, how should our scenario really look?
Scenario: Check if logged in user can apply on a job offer
Login as user X using API
Get JobOffer url and open it
--take ID from database and create url, use/prepare custom API to get an url, use part of application – whatever works
Click apply button
Fill the Apply form
Confirm Apply
Congratulation, you just cut your test execution time for about a half.
Get low, as low as you can!
One remark here – to use this approach, your application (or at least part of it) needs to be written in Service Oriented Architecture. I took backend in PHP and frontend in React for this example.
If your web application is built from services (backend and frontend), you can test most of the business logic before actual site even exists.
How? Let’s look at test pyramid.
All models are wrong; some models are useful – George Box
Probably everyone has seen that, so I won’t spend much time here. Selenium is on very top with biggest cost and smallest stability (in comparison to other types of tests, Selenium itself is quite stable). Going lower we have integration and contract tests and that’s the area I’m talking about. Cost much lower, stability and performance much higher that tests in Selenium. Perfect as a part of the service build.
Again, I won’t elaborate about contract and integration tests – there are tons of articles about it. What I want to highlight is that you can test most of the business logic on these layers. Use framework as Codeception to test backend PHP services on both layers. Check data validation, response codes – whatever you can. Similar with frontend services (react components in our case). Cypress provides the possibility to implement data validation (should we display alert for incorrect email?), user flow (will confirmation be displayed after click “Submit”?) and much more. That means, you don’t need to test all these things in selenium!
So… Do I even need Selenium?
Probably yes. You want to check if flow containing few components/services works fine but without fully testing logic of each of them. The scenario we prepared in previous paragraph is still valid. The difference is, that’s probably the only one you will need. Eventually, you tested everything else on lower layer.
Organization & Team Builder
5 年Thanks for interesting article! Some time ago I tried to write selenium tests that were doing exactly what user was supposed to do. I tried this few times and... never again! The tests were slow and bloated (and often also flaky, but that is another story). I believe you should have a selenium test for every important functionality, but it is good enough to test it once (ok, sometimes twice or thrice, but definitely no point in filling in the login form n-times).
Software Developer
5 年Horrible article. I suggest rewriting it because it seems like you are missing the point. And I suspect that was not your intention. If I just use API endpoint - I don't know if login works. I know API endpoint that can log you in works. But that's two completely different things.? Selenium can tell me if fields and buttons are rendered. Selenium can tell me if those buttons are visible (because being rendered and being visible are two different things). It can tell me that if I send incorrect data - error message I expected got displayed. It will tell me that pressing enter works just as well as pressing button. It can tell me I got redirected after I logged in. It can tell me that I got blocked after few unsuccessful attempts.? And it's especially important now. Because in React age people often forget that input can be wrapped in form tag. They forget you should not attach event handler to button click but to form submit. They forget onchange event and login and password are never filled. People forget about lot of things these days because writing react is usually more annoying and prone to errors than writing html.
Certified Test Manager, Defect Manager w Mobica
5 年ability to log in using API for example is for security reasons unadvised in some applications. Banking for example - if you can automate login page in a fast and easy way - its potentially dangerous with password guessing bots.
Test Engineering Manager
5 年As mostly I can agree with your summary about test pyramid etc. I think that whole article it's bit too general. Your example is based on simple scenario, which is quite ok for the article purpose, but what if product is developped by more than one team, in different technologies and is relying on external services/products, where number of test scenarios is counted in hundreds or even more? Relying only on lower-level testing usually doesn't work in such cases. I'm sure that there are projects/companies that made it work, but to be honest I newer saw it. On the other hand however I saw quite often when different modules were developped by vaious of teams and despite that everything was ~100% ok on each team test report, whole product had serious flaws.?
Software Security & AI Architect | Consultant | Trainer | Making the company a safer place
5 年You wrote here about using the proper tool (the type of test) to the effect you want to achieve (what exactly you want to test). Selenium testing is designed for an end to end testing including all system elements (UI, API, database, external services, etc.) and you can't just replace it with API testing because it is faster. It is faster because you limit the scope of testing. If you are ok with it, please choose the best type of test which is sufficient for you starting from the bottom of the pyramid. (https://martinfowler.com/articles/practical-test-pyramid.html) You wrote, "Don’t test more than you must!". I completely agree, but not in the way as you describe. Don't do one action by API, then in UI and then again by API. It would result in hard maintenance because you added a dependency on API layer. If you want a fast test that checks some particular action, just write pure API test, do not mix them tohether.