Finally decided on my second code challenge: this time I'm going to practice around the topic of RESTful services. Base project is there now, more to come. https://t.co/LB3fJG7dhY #CodeConfident— Elisabeth Hocke (@lisihocke) 6. März 2019
March 3
- decided on second code challenge: go one level deeper from UI to API
- https://johnfergusonsmart.com/getting-started-with-rest-api-testing-with-serenity-and-cucumber/
- decided to not use the starter repo https://github.com/serenity-bdd/serenity-rest-starter but to start locally from my previous challenge and adapt it before committing to GitHub
- decided to use Restful Booker by Mark Winteringham as target site
- decided to not use REST Assured as standalone but in combination with SerenityBDD to get nice reporting https://mvnrepository.com/artifact/net.serenity-bdd/serenity-rest-assured/2.0.40
- https://www.blazemeter.com/blog/restful-api-testing-using-serenity-and-rest-assured-a-guide
- http://www.groupkt.com/post/5c85b92f/restful-webservice-to-get-and-search-states-and-territories-of-a-country.htm
- http://www.groupkt.com/post/f2129b88/free-restful-web-services-to-consume-and-test.htm
- TODO: check out starter project structure, connect to Restful Booker, decide on Cucumber or not or both (!), adapt license, adapt readme, decide on doing Postman collection and tests there as well, or maybe doing so in a separate repo
- implemented 2 JUnit tests for Restful Booker deployed on heroku, for test purposes; test data was changed during test which made one fail; still, it's a proof of concept I can build on; maybe choose a different target under test which is more stable
- wrote test for status code and body value in Postman, really easy when using available templates
March 4
- tried to run Restful Booker locally so that maybe test data is not replaced all the time; but the Docker registry is not accessible and I didn't want to install MongoDB (editor's note: later I learned that Mongo was not required to run the app, so I could have used it as test target indeed)
- searched for other practice APIs, at best RESTful
- https://openclassrooms.com/en/courses/3432056-build-your-web-projects-with-rest-apis/3496011-identify-examples-of-rest-apis
- https://openweathermap.org/api
- https://www.smashingmagazine.com/2018/01/understanding-using-rest-api/
- use GitHub API?
- https://jsonplaceholder.typicode.com/
- https://www.guru99.com/restful-web-services.html
- build own RESTful API and test it?
- https://medium.freecodecamp.org/build-restful-api-with-authentication-under-5-minutes-using-loopback-by-expressjs-no-programming-31231b8472ca
- https://hackernoon.com/restful-api-design-step-by-step-guide-2f2c9f9fcdbf
- https://spring.io/guides/gs/rest-service/
- https://leanpub.com/testrestapi
- https://github.com/TracksApp/tracks
- https://www.compendiumdev.co.uk/page.php?title=tools
- https://www.compendiumdev.co.uk/page.php?title=restmud
March 5
- decided to follow a tutorial to create own REST service, then test it with Rest Assured: https://spring.io/guides/tutorials/bookmarks/ This way I will not only learn how to use the library, but gain a deeper understanding how RESTful services are built
- also, it's only one step further into the learning zone, as the tech stack is still familiar
- set up base project using Spring Initializr; added Serenity and REST Assured dependencies; adapted license and readme files
- created new GitHub repo, cloned it, committed base project, configured repo
March 6
- did very first part of https://spring.io/guides/tutorials/bookmarks/
- installed Lombok plugin for IntelliJ
- (did not have much time to proceed)
March 9
- followed rest of tutorial: https://spring.io/guides/tutorials/rest/
- implemented Spring HATEOAS examples (for more see https://github.com/spring-projects/spring-hateoas-examples)
- wrote first tests
- TODO: learn how to write better tests, add more
March 11
- simplified tests
- assertThat not needed, throws the same exceptions as without; REST Assured already handles it
- removed response, added and() for readability
- learned more in https://semaphoreci.com/community/tutorials/testing-rest-endpoints-using-rest-assured; e.g. that "internally, REST Assured uses Groovy and allows for Groovy expressions inside its API"
- added test setup class
- added smoke test before class, does not run any other tests in case it fails
- added test to delete employee, creating it before deletion to stay independent
- changed test formatting to become more readable, as in https://www.joecolantonio.com/rest-testing-with-java-part-two-getting-started-with-rest-assured/
- had "Invalid number of path parameters” exception; solution found in https://stackoverflow.com/questions/39917496/invalid-number-of-path-parameters-expected-0-was-3-error-while-passing-the-u --> after I used pathParam in another test I had to use it in the get first employee test, too
- TODO: find out how to do setup using Serenity Rest, implement further tests
March 12
- pairing session with Amitai Schleier
- we walked through the project, I explained my reasoning behind
- Amitai: the build step includes test, that comes unexpected
- found the included Gradle wrapper was not executable, marked it as such
- we had to add the Lombok annotation to the classpath; this came unexpected, did not already come with the repo or Gradle; we deferred identifying the root cause here; was a great reminder to run a project locally on a fresh computer from time to time to see what's missing
- Amitai: shared he would desire fast tests that can run without the app running, just triggered by a key stroke; however, this comes from the perspective of test driving an app, we're in a different context here
- we learned that the extract method was not instantly comprehensible, not clear what it's doing
- learned about fluent interfaces (see https://en.wikipedia.org/wiki/Fluent_interface); Amitai: they are nicely readable but might not be instantly comprehensible
- we both shared concerns like: do we really need to have multiple given/when/thens in a test when we only want to test one action? How to make sure the deletion test really deleted the record, e.g. by calling it again? How can we declare the base path in a nice way at one place?
- what to test for in which test? Amitai: in general he is thinking of what if this test fails, how hard do I have to think? When it goes red, how obvious is it what I have to do?
- Amitai: uses the following principle when it comes to tests: make it work, make it right, make it fast
- Amitai: using auto-format on save a lot; uses a plugin for Intellij: "Save Actions"
- we committed several changes together throughout the session :)
- we left TODOs in the code to make it obvious for any one else what's troubling and what is still worked on
- learned several IntelliJ shortcuts (for MacOS): that were new to me:
- cmd+9: toggle version control tool window; then cmd+D: on versioned file shows the diff
- option+cmd+K: commit (& push)
- option+P: push
- option+Up/Down: extend / shrink selection
- after test run, double-click on test lets us jump to the test
- retrospective:
- Amitai: already shared his feelings throughout; that was one key learning for him after all the coaching and pairing and mobbing: we don't have to wait to talk about it later, we can talk about it now
- we were feeling the same pain; how much do we have to say to set up a test; it's a screenful and shouldn't be --> could improve it a bit by reformatting and extracting the test data setup in a separate private helper method (did so); this matters as a test should be so simple that we don't need a test for it; it's supposed to serve us
- Amitai in general does like the given / when / then structure
- learned about "TDD as if you meant it" as subcategory; implement class inside test until you come across the first business object (see https://cumulative-hypotheses.org/2011/08/30/tdd-as-if-you-meant-it/)
- we shared similar concerns, like what does the test actually do, test the test, add assertion that content was actually deleted, multiple given when then steps, test setup, etc.
- we didn't use a timer, pairing was fluent, frequently switched, quite natural; we both thought of addressing it but decided to give it a go and it worked well
- I really learned a lot, curious to see how different people tackle different problems, which issues do they see, how they debug and find solutions; e.g. Amitai explored using code and the tests, would have used Postman rather as last resort to find out the behavior
- love the hands-on approach, already improved things right now, have more pointers what to improve next
- TODO: think about formatter, start using the plugin
- TODO: build step includes test
- TODO: see TODOS in the code ;)
Had a great #CodeConfident session today, #pairing with @schmonz! We shared our pain points with my current challenge https://t.co/LB3fJG7dhY and brought it to the next level 🎉 Learned so much. And the best thing is: Amitai already scheduled a second session with me! 🙌— Elisabeth Hocke (@lisihocke) 12. März 2019
March 12 (cont)
- realized when summarizing the results from the coding session that pushing from my laptop revealed my work email address; and this time we pushed 3 times, so I could not only amend the last commit like I did before (see https://www.git-tower.com/learn/git/faq/change-author-name-email)
- this time I had to rebase and edit the commits; above link showed how to do it:
git rebase -i -p 4f72861fe2fbee02da716f3442cec263e762b4b6
git commit --amend --author="lisihocke " --no-edit
git rebase --continue - problem: I pushed and merged, and new commits had been created, but the old ones were still there!
- rebased again and tried to drop these commits, but push did not do anything
- learned I need to drop them and then force push to replace the remote repo with my local one, this finally did the trick and the concerned commits are gone; feeling relieved!
git push -f - lesson learned, for the second time: be careful what you push..
March 18
- pairing session with Toyer Mamoojee
- walked him through the project, explained the reasoning behind, the targeted scope, steps taken so far, open questions
- we agreed to review what is there for our first session and later have the option to try a different test framework and/or do performance/load testing
- Toyer: first observation: usually we have test only one endpoint per file
- naming conventions for tests: have to agree with the team on that, yet should be consistent; Toyer: test name should include what you are testing for, "getEmployee" feels not enough, better "getEmployeeDetails"; also, there's a mixture right now with using "get" for reading or receiving information and "create" for posting
- Toyer: current test setup class might be sufficient for a practice project for now; would normally have the config in a separate file
- Toyer: the smoke test looks fine; what they usually do is to additionally include a test for the structure, data types, i.e. including contract testing here as well already
- Toyer: get first employee: are you sure this id exists? would extract it as constant; for test data setup they are using a separate database that can be queried, I could think about a catalog here; data should be built somewhere else to avoid duplication, in a different class generating the payload; building the payload might be more elegant as well, instead of adding properties I might create a map; creating it upfront to ensure independence makes sense; maybe can include randomizer here as well to detect more issues
- Toyer: getting information out of the response becomes impossible when you have asynchronous APIs that only return a 200, then you have to query another system
- Toyer: what else I could test for is that only 1 record is created instead of 2, checking the count of what comes back
- maybe I could also check if the generated id is not null
- Toyer: consider splitting tests based on risk; create itself might be crucial and working, only the details might be wrong
- TODO: revise project based on suggestions
Had another great #CodeConfident #pairing session on my practice project https://t.co/LB3fJG7dhY today, this time with my #LearningPartner @tottiLFC. Thank you Toyer for providing your thoughts and feedback - invaluable! We should so do that more often 😁— Elisabeth Hocke (@lisihocke) 18. März 2019
March 27
- follow-up on last pairing session
- renamed test methods to be more expressive and clearly test methods
- extracted the building of the JSON object
- temporarily switched to org.json objects, switched back to Google's gson implementation again after reading more; the biggest downside for me were the exceptions thrown
- https://stackoverflow.com/questions/42641301/org-json-jsonobject-vs-gson-library-jsonobject
- https://www.baeldung.com/java-org-json
- http://www.doublecloud.org/2015/03/gson-vs-jackson-which-to-use-for-json-in-java/
- https://blog.overops.com/the-ultimate-json-library-json-simple-vs-gson-vs-jackson-vs-json/
- https://www.baeldung.com/jackson-vs-gson
- https://medium.com/@dannydamsky99/heres-why-you-probably-shouldn-t-be-using-the-gson-library-in-2018-4bed5698b78b
- http://tutorials.jenkov.com/java-json/index.html#jackson
- https://proliferay.com/create-json-by-jackson-api/
- introduced constants for existing and non-existing employees
- added check for non-existing employee; check for message fails as response is plain text
- started research how to have JSON response for exceptions instead of plain text
- TODO: resolve todos ;)
April 21
- took up challenge again after a longer period of travels and conferences
- removed superfluous semicolon (bothered me ever since I detected it and did not find the time to remove it earlier)
- thought about running the Spring app together with the tests so you don't have to start the app in advance for the tests, like it's done for Restful Booker Platform; decided that this is out of scope for this challenge, would be interesting for a real app though
- renamed request body to payload
- potential for future: REST Assured can convert back to Java objects, don't need JSON
- ran with coverage, however nothing found covered; learned I need to run the tests on the same JVM for it to work, see https://groups.google.com/forum/#!topic/rest-assured/pzBJQqtkvS0 and https://blog.jayway.com/2014/07/04/integration-testing-a-spring-boot-application/ also, need to run as JUnit not as Gradle task it seems
- doing so I got the error "Error running 'EmployeeTests': Command line is too long. Shorten command line for EmployeeTests or also for JUnit default configuration." --> this fixed it: https://devis.cool/quick-fix/quickfix-intellij-idea-command-line-is-too-long-shorten-command-line-for/
- still, no coverage found; assume I still need the same JVM; using the Serenity Runner cannot run in same JVM, also issues with SpringRunner
- interesting post: https://medium.com/@manu.me/bdd-simplified-with-springboot-b56ffdcadb2b
- did not work so far; also having bootRun as pre-step for test did not trigger tests; however: it's okay to not solve everything in this scope
- stopped, started Test Automation University course by Bas Dijkstra that I wanted to do for so long already: "Automating your API tests with REST Assured" --> filled several knowledge gaps I had and was not aware of - awesome course!!
- added checks for content type
- this way found out how to test for the response content of plain text responses
- observation: by distracting myself / getting my mind to focus on different but related things (the course) I could solve other issues I had before; was really worth it to "unstuck" myself
- added test for updating an employee record
- considering the challenge scope officially done; I'm up for the next challenge! :)
By the way...
First: I learned once again that others appreciate the idea of keeping coding journals as well for their own learning.
Third: My feeling is I have to speed up. Only two challenges of five completed, let alone my final proof of concept app.
Last but not least: I've been pretty busy the last weeks. The good thing: although I could not work on my personal challenges, I still practiced! I've attended Automation in Testing, TestBash Brighton and Mob Programming Conference. A lot was hands-on learning which I really appreciate. Also, I can't but share one of my absolute highlights with you! Thank you Angie Jones for your encouragement, you're the best!
Second: I did not have to pause my code-confident challenge yet! I've now indeed continued playing a non-casual computer game at least once a week, and it feels great. Definitely worth following my passion and carving out time for it!Awesome! I'm doing so for my #CodeConfident challenge and it helped so far. Curious what I'll say next year 😅— Elisabeth Hocke (@lisihocke) 6. April 2019
Third: My feeling is I have to speed up. Only two challenges of five completed, let alone my final proof of concept app.
Last but not least: I've been pretty busy the last weeks. The good thing: although I could not work on my personal challenges, I still practiced! I've attended Automation in Testing, TestBash Brighton and Mob Programming Conference. A lot was hands-on learning which I really appreciate. Also, I can't but share one of my absolute highlights with you! Thank you Angie Jones for your encouragement, you're the best!
Can I take a moment to shout out @lisihocke?— Angie Jones (@techgirl1908) 4. April 2019
She attended one of my workshops last year. This year she has set a personal mission to become #CodeConfident.
She's in my new workshop today and the growth is beyond impressive! pic.twitter.com/JIvRkhFKI3
Code-Confident at TestBash Manchester
Remember when I submitted to Test.bash(); in the last hour? Well, I did not exactly get accepted for this very technical format - yet they selected me for TestBash Manchester! Simply couldn't say no to that. So, I will have yet another challenge this year: craft a presentation out of my ongoing challenge. Already playing with some ideas in my head, curious how they will work out with an audience! :)Yes! Congratulations @lisihocke for bringing your #CodeConfident tour awesomeness to #TestBash Manchester! https://t.co/cKHxCdvmEA— João Proença (@jrosaproenca) 11. April 2019
No comments:
Post a Comment