Showing posts with label codereview. Show all posts
Showing posts with label codereview. Show all posts

Sunday, November 3, 2019

On Having Become #CodeConfident

For 2019, I've once more made a pact with my learning partner Toyer Mamoojee. This year my personal challenge was to become code-confident. To learn about my hypothesis, the experiment I designed and who influenced me to embark on this journey, please read the origin story. Now that the challenge is officially over, it's time to look back and forth.

Why This Challenge

Why did I pick this challenge? This question followed me throughout the year. Here are the reasons I discovered on my journey.
  • Programming is a skill that many people benefit from; no matter their role. I think this is the case already now, and presumably even more in the future.
  • Many of my peers in the testing community program every day.
  • People say coding skills are essential for us testers. Even to stay "employable" and get new jobs. Whenever I heard this, I felt I don't belong and that soon enough everyone will see that, too. Even worse, many people consider you only technical when you're able to code. I absolutely don't share these viewpoints, but still felt the need to prove myself that I am not only able to read code but also write code myself. It was about time to conquer this fear of losing my face by showing how much I don't know yet and to see for myself how much I can increase my programming skills in a certain time frame.
  • I feel I „specialize in generalizing“ (as Patrick Prill likes to say) - so I wanted to upskill as a generalist. To strengthen my strength by adding coding to my toolbox.
  • I wanted to be able to help my testing better through automation and tool creation.
  • I wanted to understand our product architecture better, how things work together, where they tend to break, where the risks are.
  • My knowledge is quite broad yet scattered, and never really deep. I have lots of bits and pieces of knowledge and often try to puzzle them together to see the bigger picture. I wanted to see how far I can go with this when it comes to coding. The good thing: I realized I don‘t have to know everything to belong. The main key is to keep yourself aware of your contributions and the value-add you bring, and then to keep going and learning new things, adding to that toolbox you bring.


Continuous Practicing

In the beginning I found the very first steps to be the easiest and the hardest at the same time. If you want to know more, read about my first steps until picking my first coding challenge. As soon as I published my first ever GitHub commit, things started to roll.

As I started out on this coding journey, I soon felt the urge to blog about my experiences and lessons. At the same time I wanted to avoid spending too much effort on blogging and rather put it into practicing. I decided to experiment with a new lightweight blog post type in the form of a coding journal, documenting my raw notes while coding. My hope was was that these kind of posts will serve three goals.
  1. Act as learning journal for myself, making my learning journey visible helping me acknowledge what I achieved
  2. Provide context for anyone who would like to check out my repositories and maybe provide feedback and support
  3. Potentially provide a source of learning and inspiration for anyone else following my journey
So I had finally started, I blogged about my journey - next thing to do was to call for collaborators, people to pair with me hands-on or provide feedback on my code. Once more I learned about the joy of doing things together when you put trust in each other. Compared to my Testing Tour last year, I did a lot on my own as well. However, I wouldn’t be where I am without my wonderful collaborators, so here’s a huge shout out to these great people!
Not mentioned above but never forgotten are my dear teammates supporting, encouraging and teaching me during work time. Thank you.

Besides those that paired with me, this wonderful community was a great factor and motivator on my journey by providing dearly needed encouragement! Like Angie Jones who recognized my growth in her technical workshops - which meant a lot to me! She even triggered me to submit to Test.bash();. Without her I wouldn’t have presented my lessons from this challenge at TestBash Manchster. Also, during the code-related workshops I attended this year I realized people thanked me for helping them - which made me realize I was indeed able to help them!

After getting started with my first challenge, I decided to go from more familiar topics to the least familiar ones for me. So I came up with the following plan.
  1. Start with automated testing through the UI (though these tests might actually be the most complex, starting with something familiar made perfect sense to me);
  2. Then go a level deeper to API testing;
  3. Then to unit testing;
  4. Now cross over to writing features myself, first implement a small backend feature;
  5. Then implement a small frontend feature.
I hoped afterwards I would already be ready to start my proof of concept project.

Last but not least: while working on my challenges, I had to keep an eye on my self-imposed constraints.
  • Pause criteria - play computer games at least once a week
  • No online courses or tutorials - at least not for the actual practice scope
  • Time - at some point I realized I had to speed up, especially for the TestBash Manchester talk
The great news is: I fulfilled the promise to myself to have at least five repositories of practice projects published on GitHub - even in five months!

Time to Tackle the End Game

As I had hoped, I was now ready to build an application myself. I pondered for a long time what I could do as my final proof of concept app. In the end I decided to create a learning journal. An app that would help me tackle my challenges, based on what I learned so far - and other people could use the same approach. A place to define a challenge, a hypothesis, the experiment. A place to track your progress, to evaluate your results.

So this it was! I created “Journey” - a learning journal application. I wanted to use a similar tech stack to what we have at work. In the end not as similar as I intended yet still really useful for practice.

However, there‘s a twist to it. I decided to kick-start the project so I wouldn’t have to deal with the whole setup. I chose a tool called Jhipster which allows you to generate apps from scratch. Great, right? Well, this approach had upsides and downsides to it. First and foremost: I felt guilty, like I cheated by doing this jump start; while being well aware that at work we also used code generators in the beginning of a project, like the Spring Initalizer or the generated snippets by Angular. It was great to already have a running base to work on; yet the project was bloated from the beginning, with features added that I did not need (like user management or auditing). When you start something from scratch, you know everything (or most of it); with this kick-start, I felt I immediately entered a legacy project, I had to learn how things work together. Yet after all it was still valuable for practice and learning! So I decided to move on with it.

Based on the generated code I then introduced my own entities, created views, modeled what I wanted it to do. What you can do with it is you can define your challenge, and you can create journal entries for your challenge, tracking your progress. Just that, serving as proof of concept. The project is absolutely not finished yet. There's so much more to do, and so much more there could be. It would be a great playground to practice all kinds of testing as well. Though my challenge is done, I can still continue work on it - which feels amazing!

Let's Evaluate

First of all: I could prove my hypothesis true. I did practice, I paired up, and in the end I did develop a small product.

Even more: My whole year was under the focus of coding. At conferences I chose courses, workshops, and talks according to my goal. I attended sessions about mutation testing, automation in testing, clean code practices, approval testing, Python for testers, Jest, and more.

The outcome was indeed actual confidence! End of August I finally realized how much I had worked on code at work over the last weeks. I found myself writing unit tests for our new frontend, to help my developers with our safety net here and to understand our product architecture better to see where it breaks. We were experimenting with mutation testing. I even did some refactoring myself! I finally realized it was the result of having become code-confident (past tense!). To illustrate that, for example I found myself having inner dialogs like the following:
"Okay, now I’m tackling the split of this dialog component into two. Or - nah, maybe someone else should do it, they could do it more efficiently. Or maybe we do it together! Pairing is great. Well, let's have a short look at it first. Oh, that looks like more than I thought it would... Well, whatever, let’s try anyways."
And I was able to do it! In addition, by doing so I understood our application a lot better. The thing is: I would have been capable of doing this before already - yet I didn’t dare to do so. I hesitated, found excuses.  Now I am not afraid anymore to try and to learn by doing. I know there’s a lot more to learn - and that’s fine!
All this made me think. I could stop now with confidence - yet what about if I dare even more? Step even more out of my comfort zone? When preparing my TestBash talk about this whole challenge, my original idea was to have no slides at all, just code, walking people through. Well - obviously I still had slides in the end, I did not dare go without them (yet!). Still I wanted to dare even more. So I decided to do some live coding on stage to show my confidence. I considered that this might go horribly wrong - yet at least I would have tried it. I thought, even if I failed I would have succeeded as I would have dared; and I would have learned what not to do in these situations. ;-) So I prepared for it. I chose my proof of concept project Journey as my target app. I chose a super small change to make it less scary, to not take too long, something that would still allow me to narrate what I am doing at the same time. Small steps, right? Also, I chose a frontend change so people could see the impact right away without me having to restart the app. So that's how I did it - and it worked out!

Plenty of Lessons Learned

There are a lot of lessons to take away from this journey. Let's start with the lessons learned when working with code.
  • Learn how to go in small steps. And then even smaller steps.
  • Googling is a real skill - if you know what to look for it will save you lots of time.
  • Read things carefully. Documentation, exceptions, what methods expect - don't skim over them but read them properly! Sometimes you really need to read everything to get the information you need.
  • Keep maintenance in mind. Would a method now take more than three parameters? Then it's time to refactor as it's getting too big to keep it in the head. One method, one purpose; keep it small. Shall we extract a method for a line that's used in two places? It might not be worth the effort, yet should be consistent. The most elegant solution might not be most readable one, find the middle way.
  • Test the tests. I encountered this classic several times: a test that's constantly green but not checking the right thing (or no thing at all). Sigh.
  • Learn IDE shortcuts by heart; especially for all features you constantly use.
When it comes to code review:
  • Get feedback early and incrementally.
  • Don’t take it personal.
  • Learn from it.
  • Thank people for their feedback.
  • Respond to each feedback.
  • Need to discuss? Then rather discuss in person.
  • Stay patient.
  • It’s scary but worth it!
And finally, I also learned a lot on the personal challenge itself.
  • Learning by exploring is really valuable (and very close to our everyday work). I have a hunch, thought, that it might be best combined with some more structured training.
  • In the end it’s all about practice, practice, practice. It's not about doing things perfect from the start, but about daring imperfection and getting feedback to improve.
  • Pair up for success. (Obviously.)
  • Follow your energies and don’t forget to take breaks. Tired days are not helping. For a private project you have the luxury of leaving a problem for a while and follow your energies instead to keep the momentum. After a while you can either come back to the problem or leave it there (if it’s just for practice); at work we often have to push through, yet defocusing can still help there as well.
Overall, I learned a lot! But I also struggled a lot. My biggest struggle increased my empathy for my developers. Not only the kind of work they do as problem solvers, or having your own work reviewed, but especially when it comes to testing.

When developing I caught myself just wanting to make things work and then move on. The sad truth is, I postponed errors. I sometimes did not test a change at all, neither using exploration nor automation. I just wanted to move to the next change and the next and the next… I really should know better and yet did not care! (Still can't believe this. Super embarrassing.) I really had to remind myself of switching between development and testing modes, or rather intertwine them. This is not easy and I will need to continue practicing. Now I know better how they feel and how difficult it can be to not jump to the next feature.


What else?

Besides this challenge: I‘m finally enjoying my hobby again! As I promised to myself, I played a computer game each week since 2018, December 16th. :D Yet honestly, I struggled to achieve even that. I did not play too much each week. The sad truth is, I dearly needed this personal limit to take better care of myself. So, I'm still working on finding a better balance. We should not put our personal lives behind our personal development.

Now that I survived puzzling bits and pieces of knowledge together to create something myself - I can go back to school! :-) I wanted to fill my theoretical knowledge gaps and get a deeper understanding of the languages, or at least revisit the basics. To begin with, I finally did a bunch of more courses offered by the Test Automation University. By doing so, I discovered that I knew a lot of these things already! This kind of confirmation is a really encouraging. Also, this made me revisit some important concepts that I had heard of already yet never really memorized. As a side effect, I know now that these courses are very worth recommending, they are well taught and provide a wealth of easily accessible, free knowledge. If you haven't done so already, check them out.

At work, I continued to contribute in new ways, using and practicing my coding skills a lot more. This feels so good! Especially as researching real problems open up so many opportunities to learn more.

Oh, and I'm sure there will be another personal challenge for 2020! :-) I'm already thinking about it. Yet no matter what I might choose, I already made a decision to continuously offer pairing sessions, on various topics. Over the last years this proved to be extremely beneficial to all parties. In case you're up for it, feel free to check my availability for the next period on Calendly and book a session with me.

In Summary

If you want to go on your own journey and tackle your own challenge, then break it down so it becomes testable and therefore achievable. Explore using the knowledge you already picked up on your way, and practice! Yet always remember: take care of yourself first.

Sunday, August 18, 2019

#CodeConfident: Journey - Part 2

My Journey project made some progress! It's still far from where I'd like it to be, yet here's another part of my coding journal - including three more pairing sessions and a brief detour to my former Rest Practice project. Enjoy! :)

July 14

  • pairing session with Parveen Khan
  • when preparing for my pairing session, I removed all built directories and have the project build from scratch - which indeed proved my assumption that this would fix the profile service! :D
  • in the beginning I told her about the background of the app, did a short run through of the app, explained what had been generated and what I added or changed, and what are potential next things to do
  • Parveen wanted to explore the app and then do first changes together
  • when Parveen went through the app, we noticed several things, she raised lots of great questions and she triggered several ideas what to do next
    • TODO: the create / update challenge dialog showed the "influences" label in lowercase although it should be uppercase
    • TODO: the journal entry index page should sort entries by default by date in a descending way with the latest one on top (right now sorted by creation date)
    • TODO: for the index pages, the pagination thresholds should be defined, e.g. only showing 10 items per page
    • IDEA: Parveen asked me whether I wanted to use the app to instantly publish journal entries to my blog - and I thought of that indeed! Or at least to have a quick copy button for the description field so I could easily copy it over to my blog posts and make my own life easier
    • TODO: showing the challenge id for journal entries is not really useful, should rather show the tag instead (had that one on my list, yet it's great to hear confirmation from a different person that this should change)
    • TODO: the challenge delete dialog should not only ask for confirmation of the deletion but also inform what will happen with potential related journal entries
    • TODO: when trying to delete a challenge that still has journal entries, an unhelpful error 500 is thrown and the error message is not useful at all
  • then we went on with making small changes to the app and seeing their impact
  • for the challenge index view, we added a column for the hypothesis
  • for the journal entry index view, we wanted to do the same, yet decided not to dive deeper here for now and solve that puzzle yet
  • instead we changed the challenge detail view to not show the challenge id in the title yet the tag instead, and removed the tag from the rest of the detail page
  • IDEA: we found it would be great to see related journal entries also in the challenge detail view
  • Reflecting:
    • Lisi: having a practice project offers a great and safe learning environment to get your toes wet
    • Parveen: you need to have some idea of what app you want, then you start with small steps, then you get used to it, and you keep trying
    • Parveen: having me as trusted navigator gave her the confidence to do these changes herself; also, I gave her the confidence by telling her "it's fine, don't worry", "we can just delete it, we have it under version control" and letting her do it on her own and try things out; Lisi: it was super useful to practice explaining things I learned (some of them recently), especially in a simple way, really helps my own learning; this is also something such safe learning environments are perfect for
    • Parveen: was super great to both explore an app and make changes within just one hour! Now she understands why developers get into the zone, even forgetting to eat, doing things step by step; all this really helps to get into their shoes and create empathy
    • Lisi: was really cool, got a lot of ideas out of the session :D

July 14 (cont)


July 21


July 24


July 25


July 27


July 28

  • looking at examples from work
  • tried more things
  • really need to read more deeper first
  • nothing committed yet

August 11

  • pairing with Shivani Gaba
  • We planned to set out to pair on my Rest Practice project for which Shivani had feedback to share based on her experience with automated API tests.
  • Shortly before the call I realized that the framework used in this project was relying on Java 8 which I recently had removed from my computer so we could not run the tests. After spending some time back and forth how to install OpenJDK 8 so I would not need the Oracle version, we decided to go through the feedback first. (Later I found this site where I could download a pre-built version of OpenJDK 8 for Windows: https://adoptopenjdk.net/)
  • Instead of always using an explicit status code (e.g. 200), Shivani recommended to use predefined response status types so that the test becomes more readable and less error-prone.
    https://docs.oracle.com/javaee/7/api/javax/ws/rs/core/Response.Status.html
    https://www.programcreek.com/java-api-examples/javax.ws.rs.core.Response.Status
  • In the current tests I asserted for certain body properties. Shivani recommended to implement a JSON helper instead which would provide utility methods like comparing the actual response to an expected JSON. This comes in handy especially if you have a lot more fields to test for. Also, this helper could offer generic convenience methods for creating a JSON object with certain parameters, adding and removing properties, or merging JSONs. Shivani offered to provide a sample - thank you!!
  • Shivani recommended to store the complete response in a variable from which we can then extract headers, body, code whatever we need/want to use for each test only what's needed for the specific test.
  • All endpoints were repeated in each test. Shivani would rather extract them as global enums (e.g. something like "Employee.GET_ID"), or at least declare them as variable, and re-use them, which would also increase readability and maintainability. If they change, you only need to change them in one place.
  • One open question in the practice project was how to get a response without given/when/then when it's only about the setup. Shivani shared how she would wrap the setup in a custom method (e.g. a post method) to hide this implementation details from the rest of the test, which makes it more readable and more maintainable as well.
  • At this point we decided to switch to my Journey project and have a look at how integration tests are done there. I explained the background and purpose of the project, what JHipster already brought with it, and that most of the tests got auto-generated and need improvement.
  • We took the test for creating a journal entry as an example to start with. I shared that what surprised me with the generated tests was that they check the database directly instead of calling the API again to verify if the record really got created. This might be good as it's about testing the integration with the database, yet I was not so sure about depending on the database state here. Shivani did not work with Spring and its test context yet, yet this surprised her as well.
  • Shivani shared that oftentimes integration tests are only used for the happy path, yet they are perfect for negative testing as well. For example, what if a mandatory field is not there? How do we handle that? We decided to implement a test for that to learn how it's done with the Spring framework. We discovered we could simply set a mandatory field to null before creating the DTO out of the entity which led to a bad request we could assert for.
  • We learned more about how the Spring framework builds requests and uses matchers for assertions.
  • We did not yet find a way how to provide custom error messages this way, like we could do for AssertThat().
  • We found a more readable and re-usable way how to write the tests, extracting the expected response and the builder which made the test more lean. We could do this globally to reduce duplication.
    https://www.logicbig.com/how-to/code-snippets/jcode-spring-mvc-junit-test.html
  • Reflection:
    • I was really sorry for the rough start and the delay before we could work hands-on together. I was not as prepared for the session as I wanted to be, had a bad day. In the session I gained a lot new insights and good practices how to improve readability and maintainability of API tests. Thanks so much for sharing your experience Shivani!
    • Shivani shared she was happy to pair with me. It got her really motivated to work on her own project idea now; something she had in mind for longer yet did not start yet :)

August 15

  • Pairing session with Gem Hill on unit tests
  • Gem is starting her own testing tour and I felt super honored to be the first stop on her tour! :D For more details see https://letstalkabouttests.xyz/index.php/testing-tour/
  • We started with me explaining the background of my Journey project, what it's supposed to do and also the code generation part, showing Gem what's there.
  • We wanted to dive deeper into unit tests, and we had quite some generated tests to look into to understand them better and also critically question them.
  • We decided to dive into the frontend unit tests using Jest as Gem's team is now also working with TypeScript and Jest, so this was a perfect match; and also for me it was great as currently I am working on frontend unit tests as well at work in a similar setup.
  • I shortly introduced Jest and it's super useful watch feature where it runs all time in the background, running tests for changed files to quickly provide feedback while developing (my colleagues love that feature).
  • We decided to look at the test for the challenge detail component first as most simple starting point.
  • We went through the test from top til bottom, trying to formulate our understanding, making assumptions clear, voicing questions and parts we don't understand yet.
  • Then we had a look at the actual implementation to map it to what we saw in the test.
  • We noticed that the tested ngOnInit function only subscribed to the challenge, yet the subscription was not tested. This part is basic functionality provided from the framework - which is normally not what we want to test. So it's always the question where do we trust the framework implementation?
  • We had a closer look at the mocking part. Interesting to dive deeper into would be the ComponentFixture class which is provided by Angular as fixture for testing and debugging components. This is something we're not using at work so I'm curious to find out more.
  • The test is importing a test module which comes with a lot of mocks for services.
  • When looking at the test module we came across the same number used for ids again, "123" - it seems the JHipster developers used the same number for all kinds of ids. To make sure our test is independent we changed the id for the used challenge and the tests promptly failed. Here we could see how Jest points out differences. I am also using the Jest plugin for Visual Studio Code which even shows the error inline. That's a nice feature, yet for me it's easier and quicker to see what went wrong in the console output.
  • We decided to move on to another test and chose the assumed next smallest one, the one for the delete component.
  • Here we came across the fakeAsync() and tick() methods which caught our interest. Once again we enjoyed the Visual Studio Code feature to hover over a method to get its description :) We learned that tick() simulates the asynchronous passage of time.
  • We discussed spies which allow to mock return values of functions to stay independent from other parts of the app.
  • Gem suggested to interact with the locally running app and see what's actually happening. This triggered the idea that I should install the Redux DevTools so we could inspect even closer. For now, we deleted a challenge and checked the respective requests sent. This way we saw that opening the delete dialog sends a GET request for the respective challenge - why? We had a look at the implementation and saw the defined selector. Was this the reason? We checked all references yet it was only defined here. We could not yet clearly see how things connect here, something to find out later.
  • We had a look at the implementation for deletion and found a method to close the dialog on cancel. Once again we asked ourselves, is this worth writing a test for? Is it worth the effort of maintaining such a test? This should normally be code that's not touched very often so it's probably not worth it.
  • We discussed mutation testing, an approach my team is currently trying out and Gem used quite often in the past. This is a great way to see if our tests are actually valuable and would detect issues and where we are missing tests. In my team we plan to use this as better guideline for what to write tests for than mere coverage which is not as helpful.
  • Another part that caught our interest was that on deletion, an event gets broadcasted and the dialog closed. In the test, however, not the actual methods but respective spy methods had been used: dismissSpy() and broadcastSpy(). We assumed this makes the unit test even more "unit". Another point to dive into deeper!
  • We moved on to the next test, this time the more complex one for updating the component. Once again, we started from top, including the imports. Gem called out that it's interesting that a HttpResponse is imported, came unexpected.
  • We also once more saw that the test was named "Challenge Management Update Component", as it was generated - we both found it weird that the word "management" was included here.
  • We had a look at the test for saving. It's really great that the generated tests included comments for given / when / then which made them easier to read and understand. This test, interestingly, also showed a comment for the tick() method which the other test lacked!
  • We checked the differences for updating and creating a challenge, both on test and implementation side.
  • What caught our eye was a boolean called isSaving. We wondered what it would do? We decided to first interact with the app again to see what's actually happening. A GET request, a PUT request. Nothing unexpected. Then we had a look at the implementation for isSaving. And we found this boolean is set to true only during the time the actual saving process is taking place. The value is only used in the tests. We both found this very weird. We would not expect this kind of implementation just for the tests, we never saw something like this in the products we worked on. We would only expect to add this during debugging to see what's going on; yet for the test it felt strange and it didn't feel to provide any value. I took a note to remove this implementation later on.
  • Reflection:
    • Time was flying and we soon got to the end of our 90min timebox.
    • We both found it really nice to take time and dissect unit tests, challenging them, asking why, finding issues and questions while learning about the product. It proved again the point that you don't need to know code to the extent a developer does to be able to use your skills and strengths as a tester on code.
    • I absolutely enjoyed our pairing session. When pairing we both bring our skills, expertise and knowledge to the table, and Gem and I had both overlapping and differing knowledge which fit together nicely.
    • When pairing I realized how valuable it is to also look at the imports! I normally skipped them, yet we can already raise questions and improve our understanding here.
    • It was great that Gem reminded me to interact with the real product again. I tend to focus too narrowly on what's in front of me which in this case is the code base, so it's easy to get disconnected. I noticed this several times now already during my code-confident challenge, catching myself on things I should know better. Gem pointed out this needs a context switch which is not easy. I agree, and it also increased my empathy towards my developers a lot more.
    • Gem noticed me taking notes and realized she should also think about how to take notes better for her next stops on her testing tour.
    • Gem found JHipster really intriguing. All the weirdness and bloatiness aside it seems to be really valuable to quickly kick-start a project and be able to learn with it. She plans to generate her own project for further learning purpose.
    • We both found it super easy to pair with each other, even though we only met a few times in real life or virtually and paired only once before. Time flew by and we both were energized afterwards!
    • I'm super looking forward to hearing more about Gem's testing tour and the lessons she will learn on her way :)
  • TODO:
    • install the Redux DevTools
    • remove isSaving boolean

What else?

The next Ministry of Testing Power Hour is coming up! I'm excited to be the one answering all your questions about pairing and mobbing. Just ask them at the club, and on August 22nd I'll answer them from my experience.
Also, the call for collaboration for European Testing Conference is open! Seize the opportunity to participate in this amazing conference next year by proposing your session ideas. The submission alone is worth it as you will get invaluable feedback.

Sunday, March 3, 2019

#CodeConfident: Serenity Cucumber Practice - Part 2

If you've read the coding journal of my first #CodeConfident challenge, you know that I've called for collaboration. The great thing: people followed the call! Many thanks to those who gave feedback on my first public code challenge serenity-cucumber-practice. Here's how the story continues and the project evolved.

February 7

  • received the following code review feedback from Peter Kofler:
  • "The Java language `assert` should not be used in tests. It can be disabled (is disabled by default) and does not give a good error message. I recommend using `assertEquals(expected, actual):` I see Serenity comes with AssertJ includes. I recommend using that. Open http://thucydides.info/docs/serenity-staging/ and search for assertj."
    --> switched from Java assert to use AssertJ assertions (http://joel-costigliola.github.io/assertj/assertj-core-quick-start.html); now understood why the Java asserts did not provide me as great messages as the Groovy asserts we use at work (note to myself: should have questioned that earlier...)
    --> "Thanks a lot! I already wondered why the asserts did not provide me a decent message. Switched to AssertJ assertions now, definitely a way better option :)"
  • "You do not have to create a branch for a work in progress test. Instead mark it as pending. E.g. Cucumber's "@wip" in the feature file ignores the scenario. Here are some options https://stackoverflow.com/q/3064078/104143"
    --> added option to ignore certain features & scenarios, excluding the tag from the Cucumber test runner
    --> "Thanks! I am aware I don't have to create branches to try things out. In this special case I decided to go for a branch as I was already suspecting that my approach is flawed and won't work. I only wanted to keep the work for reference and to receive feedback on it. Still, I now added the option to ignore single features or scenarios, something I was aware of but had not included here. Thanks for the hint!"
  • "All methods in this file are too long. Maybe split out chunks of coherent logic into helper methods. E.g. line 125-132 could go into a `createProductJsonItem()` method. Also building the request should go into another method. The remaining top level method will be easier to understand."
    --> did not think of this as this was "only" playground code - and yet it still makes any code harder to read, even if it's throw-away code; so, split parts into helper methods
    --> "Good point, thanks! I've now split parts into helper methods."

February 25

  • first #CodeConfident live pairing session with João Proença
  • I showed the project status, shared the struggles with the remove item from cart scenario
    • João: let's first see what it really does; inspected the add to cart button
    • we learned we can simply use the URL call sent on adding an item to the cart ("http://automationpractice.com/index.php?controller=cart&add=1&id_product=1&token=e817bb0705dd58da8db074c69f729fd8"); learned that the token parameter is not needed, but this call only works in case you have a session first, so need to access the page in general in the same browser session first; --> we implemented this approach and it worked! :D
    • there are still problems with it, like the usage of a hardcoded product id; we are depending on its existence; João would rather use the product name or something; using a proper API to create our test data would be best
    • João is using a lot of subcutaneous testing for his product, using an API that's exactly called as the UI calls it, would increase testability here a lot
    • test data management is a really complex topic; they first tried the approach to set up the complete data before any test suite run, which turned into a big monster; now they are offering methods to create test data on demand when needed for each scenario; we use the latter approach at work, too
    • I learned what I missed when searching for a solution myself: the exploratory mindset when approaching an automation problem, I already jumped to approaches I knew
  • another problem João sees: usage of product ids in the feature files is not nice; would rather use the product name
    • João explored the URLs found in the source, could not find something suitable; "?name_product=Blouse" or "?name=Blouse" were not working
    • ideas: we could 1) maintain a sort of dictionary in the code to map id and names, 2) use any product randomly but we would loose deterministic characteristic of the test, 3) hide the product id to lower levels as we don't care which one is used (in our product we often use the third approach)
  • I shared my challenge to hover over category menus
    • João would try an implementation to hover over the element then debug the test and see what's really happening; would probably need to wait that submenu is displayed, would check that style is changed to block
    • afair the problem was finding the element to hover over; João: maybe the element did not have the hover, seems the <li> has it
  • retrospective: for João it was a really cool session, these kind of exercises always trigger interesting discussion, e.g. around test data management, that the Serenity session offers to pass over variables between steps, and more; was really productive for him; Lisi: was really cool, the biggest learning was to see João's approach how to tackled these challenges, realized I got stuck in my boxes when tackling different challenges but should rather combine all skills I have; the short coding part together was nice too, would like to see more of that in future sessions, but also had really interesting discussions, was eye-opening overall; João: I'm not coding all the time, I'm not the person for that, rather trying to figure out shortcuts like calling the URL, I saw the URL and found it interesting so I tried things there; it's really about combining the skills to the problem, it's not just coding
  • TODO: commit solution, hide product ids, try again hover scenario, add update quantity scenario
  • TODO: update blog post / create new one, including code review from Peter and session with João; ask both first whether they are okay with that!
  • TODO: select next challenge
  • reflection before session and afterwards: we did it now quite similar to Angie Jones' proposal: http://angiejones.tech/hybrid-tests-automation-pyramid/
  • realized that the needed URL was only given when inspecting the "add to cart" button on the search page, not on the product page itself!


February 25 (cont)


February 26

  • hid product ids from shopping cart scenario steps, don't care which product it is
  • TODO: try again hover scenario, add update quantity scenario
  • TODO: create blog post with code review from Peter and session with João
  • TODO: select next challenge

February 27

  • aimed to implement hover scenario
  • tests suddenly get ignored and therefore skipped! found it's related to the tags used to mark parts to be ignored; as soon as no scenario is ignored the tests run; found that ignoring single scenarios still worked, but ignoring a whole feature file will lead to the not ignored one to be skipped! updating Gradle dependencies, rebuilding project, restarting, etc. did all not solve the issue; updated Serenity libraries to latest version --> now feature level tags work again!
  • found that TightVNC can auto-scale the window, more useful for my case than TigerVNC on Windows
  • found a way to navigate to the desired category (not elegant, but it's working)
  • found that the assertion failed and yet the scenario was marked as passed! IntelliJ warned that the assertion result is indeed ignored; using a JUnit assert the assertion throws... lesson learned: sometimes it helps to walk away, take a break, then have a look again; this way I found that I set a bracket at the wrong spot so I did not really assert for something
  • cleaned up
  • TODO: add update quantity scenario
  • TODO: create blog post with code review from Peter and session with João
  • TODO: select next challenge

February 28

  • implemented update quantity scenario
  • got annoyed by rewriting camel case to snake case, so installed this plugin to switch easily: http://plugins.jetbrains.com/plugin/7160-camelcase
  • speed of implementing very first attempt heavily increased the last days when practicing more regularly :)
  • remembered how to wait for expected condition
  • remembered how to cast different data types in Java
  • remembered regex for numbers
  • realized code style inconsistency, having step definitions in snake case and all other methods in camel case; unified it in favor of camel case
  • TODO: create blog post with code review from Peter and session with João

What else, what's next?

A few more pairing sessions had been arranged already. We will decide on the challenges to tackle together when the sessions get closer. In case you'd like to become a part of my journey, feel free to schedule a session with me as well.

Although I had not planned to do so this year, Angie Jones triggered me to submit to Test.bash(); - and in the end I could not resist any longer. The topic? My code-confident challenge of course. Fingers crossed!
Besides that, my Test Automation University course "The Whole Team Approach to Continuous Testing" is finally recorded and about to go live soon - which means I have my focus back on becoming code-confident. I'm about to choose my second code challenge these days, so stay tuned for more!