<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Osanda Deshan Nimalarathna on Medium]]></title>
        <description><![CDATA[Stories by Osanda Deshan Nimalarathna on Medium]]></description>
        <link>https://medium.com/@osandadeshan?source=rss-5f8c496591b5------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*4pUFOS2h9CYLiQE18XWt0w.jpeg</url>
            <title>Stories by Osanda Deshan Nimalarathna on Medium</title>
            <link>https://medium.com/@osandadeshan?source=rss-5f8c496591b5------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 01 Jun 2026 08:26:51 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@osandadeshan/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[My Engineering Manager asked for a test coverage dashboard. Here’s what I built]]></title>
            <link>https://medium.com/automationmaster/my-engineering-manager-asked-for-a-test-coverage-dashboard-heres-what-i-built-55b81b789327?source=rss-5f8c496591b5------2</link>
            <guid isPermaLink="false">https://medium.com/p/55b81b789327</guid>
            <category><![CDATA[web-automation]]></category>
            <category><![CDATA[automation-engineering]]></category>
            <category><![CDATA[test-automation]]></category>
            <category><![CDATA[test-coverage-report]]></category>
            <category><![CDATA[test-coverage]]></category>
            <dc:creator><![CDATA[Osanda Deshan Nimalarathna]]></dc:creator>
            <pubDate>Sun, 01 Mar 2026 13:46:03 GMT</pubDate>
            <atom:updated>2026-03-02T08:01:29.842Z</atom:updated>
            <content:encoded><![CDATA[<h4>Automation test coverage report with GitHub Actions and GitHub Pages</h4><p>A few weeks ago, my Engineering Manager came to me with a simple ask:</p><blockquote><em>“Can we have a dashboard where I can see how much of our end-to-end test coverage is actually automated?”</em></blockquote><p>Simple question. Not so simple answer.</p><p>We had a Cucumber + Playwright test suite running in a Gradle Kotlin project, with feature files neatly sitting inside the repository. But there was no easy way for anyone outside the QE team to see at a glance — “hey, we have 40 features, and 80% of the planned scenarios are covered by automation.”</p><p>So I sat down and figured it out. Here’s the full story.</p><h3>First, we had to decide where to track the scenarios</h3><p>Before writing a single line of code, I had a conversation with my engineering manager and head of QE about where we’d actually store the E2E scenario data that we’d measure coverage against. We came up with three options.</p><h4>Option 1: Jira</h4><p>The idea was to create and maintain E2E scenarios as Jira issues, link them to features or epics, and then use the Jira API to pull counts and calculate coverage. The formula would be straightforward:</p><p><strong>Automation Coverage % = (Automated Scenarios / Total Defined Scenarios) × 100</strong></p><p>The pros were real. You’d get full traceability from feature to story to scenario to automation. It scales well. It fits nicely into engineering governance.</p><p>But the cons were just as real. You’d need to document every single existing scenario in Jira first — a significant upfront effort as we don’t have any test case in Jira. You’d need to manage a Jira API token. And every PR would need to make live API calls to Jira, which adds latency and a hard external dependency to your CI pipeline.</p><h4>Option 2: A shared Excel/Google Sheet</h4><p>Keep a spreadsheet with three columns: feature name, scenario name, and status (Automated / Not Automated). A Python script reads it and does the math.</p><p>Quick to set up. No tokens needed.</p><p>But spreadsheets have a way of rotting quietly. Ownership gets fuzzy. Even though Google Sheets has version history, it’s not very useful for developers. People may forget to update it. After six months it becomes a liability rather than an asset. Not ideal.</p><h4>Option 3: A CSV file inside the repository</h4><p>Keep a simple CSV file right inside the E2E test repository. Two columns: feature name and total planned scenario count. A Python script reads it directly during the CI run.</p><p>No Jira dependency. No external API calls. No spreadsheet chaos. The data lives right next to the code it describes, so it gets reviewed in the same pull requests.</p><p>The trade-off is honest and manageable: the QE team needs to remember to update the CSV whenever they add new features or change scenario counts. That’s it.</p><h3>We decided to go with option 3</h3><p>For our team’s situation, this was the right call. We didn’t have Xray or any Jira test management plugin in place, and setting that up just to get a coverage number felt like over-engineering. The CSV approach kept the solution inside our own repository, under version control, with no external dependencies touching our CI pipeline.</p><p>The QE team owns the CSV. When they add a new feature file, they add a row to the CSV. Simple contract, easy to enforce in code review.</p><h3>What I actually built</h3><p>With the approach decided, here’s what the solution looks like end to end.</p><h4>The CSV file</h4><p>A file called planned-automation-tests.csv sits in the repository under the src/test/resources/features directory . It looks like this:</p><pre>Feature,Planned Automation Test Count<br>Login,6<br>Navigation Bar,12<br>Checkout,8<br>User Profile,5</pre><h4>The Python script</h4><p>A script called generate_coverage.py reads the CSV, walks through the actual .feature files in the repository, counts how many scenarios are automated (by counting Scenario: and Scenario Outline: lines), and produces two outputs:</p><ul><li>A Markdown formatted feature coverage summary as a PR comment</li><li>A standalone HTML report for the live dashboard</li></ul><p>The Python script will generate a Markdown comment using the template located at scripts/test-coverage-report/templates/test-coverage.md.tpl.</p><p>It will also generate an HTML report based on the same template found at scripts/test-coverage-report/templates/test-coverage.md.tpl.</p><p>The coverage percentage per feature is simply the automated count divided by the planned count from the CSV.</p><h3>The coverage report dashboard</h3><p>This is the part I’m most happy with. The HTML report isn’t just a plain table — it’s a proper interactive dashboard with dark theme styling that I’m hosting for free on GitHub Pages.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*K4a1GN8zoZSLrdwyIef3Dw.png" /><figcaption>Automation Test Coverage HTML Report</figcaption></figure><p>At the top of the report, four summary cards give an instant health check at a glance:</p><ul><li><strong>Overall Coverage %</strong> — the combined coverage across all features, with a colour-coded progress bar (green when high, amber when moderate, red when low)</li><li><strong>Total Planned</strong> — total scenarios defined across all features in the CSV</li><li><strong>Total Automated</strong> — total scenarios actually implemented across all feature files</li><li><strong>Total Missing</strong> — how many scenarios are planned but not yet automated</li></ul><p>These four numbers are the first thing my Engineering Manager looks at. He doesn’t need to scroll a table to understand where we stand.</p><h4>Search, sort, and filter</h4><p>The table below the summary cards isn’t static. It has three interactive controls built in.</p><ul><li><strong>Search</strong> — a search box at the top lets you type any feature name and the table filters in real time. If you have 30+ features, this saves a lot of scrolling.</li><li><strong>Sort</strong> — every column header is clickable and toggles between ascending and descending order. You can sort by feature name alphabetically, by planned count, by automated count, by coverage percentage, or by missing count. The most useful one in practice is sorting by coverage percentage ascending — it immediately surfaces the features with the lowest coverage so the team knows where to focus next.</li><li><strong>Filter by coverage tier</strong> — a dropdown above the Coverage % column lets you filter by health status. The three tiers are:<br>🟢 <strong>≥ 90%</strong> — well covered<br>🟡 <strong>80–89%</strong> — getting there<br>🔴 <strong>&lt; 80%</strong> — needs attention</li></ul><p>Each row’s coverage badge is colour-coded to match these tiers, so the table is easy to scan even without using the filter.</p><h4>The “Missing from CSV” warning</h4><p>This one saved us from a real problem in the first week.</p><p>When a QE engineer adds a new .feature file to the repository but forgets to add a corresponding row to the CSV, the script detects it. It knows the feature file exists (because it can see it in the repo) but has no planned count to measure against.</p><p>Instead of silently skipping it or crashing, the report handles it in two ways. First, a warning banner appears at the top of the table.</p><p><strong><em>⚠️ Attention:</em></strong><em> Some feature files exist but are not included in </em><em>planned-automation-tests.csv. Please define their planned automation test count to ensure accurate coverage reporting.</em></p><p>Second, the affected row appears in the table with a warning icon (<strong><em>⚠️) </em></strong>and a tooltip <em>“Feature not defined in planned-automation-tests.csv”</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3HMkrwPG5dhSrli9oYfdkw.png" /><figcaption>Missing feature file in the planned-automation-tests.csv</figcaption></figure><p>This means the oversight gets caught as soon as the next report generates — either during the PR review or after merge when the dashboard updates. The QE engineer sees it, goes back, adds the CSV row, and raises another PR. It’s a lightweight safety net that keeps the data honest without requiring any manual audit process.</p><h3>The GitHub Actions pipeline</h3><p>The CI pipeline is where all of this gets automated. The workflow has four stages, and the design decisions behind each one matter.</p><h4>Stage 1 — Build</h4><p>Runs mvn -B clean compile to verify the project compiles. Every PR triggers this regardless of what files changed. This is the baseline check.</p><h4>Stage 2 — Test</h4><p>Installs Chrome, runs the full Cucumber test suite using mvn clean test -Pheadless-chrome,qa, and uploads the test report as a build artifact. Again, this runs on every PR — not just ones that touch feature files. You always want your tests to run on every change.</p><h4>Stage 3 — Report (PR coverage comment)</h4><p>This stage is smarter. It only does meaningful work when a PR actually changes a .feature file. Here&#39;s how that works:</p><pre>- name: Detect Feature File Changes<br>  id: changes<br>  uses: dorny/paths-filter@v3<br>  with:<br>    filters: |<br>      features:<br>        - &#39;src/test/resources/features/**/*.feature&#39;</pre><p>If steps.changes.outputs.features == &#39;true&#39;, the stage runs generate_coverage.py, uploads the HTML as a build artifact, and posts a Markdown coverage summary as a comment directly on the PR. The comment includes a table of all features with their planned, automated, and missing counts, plus a link to the full HTML report artifact.</p><p>If no feature files changed in the PR, every coverage step is skipped and a simple “⏭️ No feature file changes detected — skipping coverage report and PR comment.” notice appears in the log. No noise. No redundant comments on PRs that have nothing to do with test coverage.</p><h4>Stage 4 — Deploy to GitHub pages</h4><p>The deploy stage only runs on a push to master — meaning a merged PR. It applies the same path filter logic: if no feature files were part of the merge, the entire deploy is skipped. If feature files did change, it regenerates the report fresh from the merged codebase and pushes it to GitHub Pages.</p><pre>deploy:<br>  if: github.event_name == &#39;push&#39; &amp;&amp; github.ref == &#39;refs/heads/master&#39;</pre><p>A key detail here is that each GitHub Actions job runs on a completely fresh runner. Files generated in one job don’t carry over to another. So the deploy job doesn’t try to download the artifact from the report job — it runs generate_coverage.py again independently. This makes the deploy stage fully self-contained and resilient.</p><h4>The trigger design</h4><p>The trigger setup is something I had to think carefully about:</p><pre>on:<br>  pull_request:      # ALL PRs trigger build + test<br>  push:<br>    branches:<br>      - master       # Merges to master trigger deploy</pre><p>There’s no paths filter on the pull_request trigger. I made this mistake initially — I had set it to only trigger when feature files changed, which meant PRs that touched only Java code didn&#39;t run any CI at all. Build and test were being skipped silently.</p><p>The fix was to let all PRs trigger the workflow, and move the feature file filtering inside the specific jobs that need it. Build and test always run. Coverage reporting only runs when it’s relevant.</p><h4>A verification step before every deployment</h4><p>One more thing I added to the deploy stage is a verification step before it tries to copy and publish anything:</p><pre>- name: Verify coverage report was generated<br>  run: |<br>    if [ ! -f artifacts/feature-coverage.html ]; then<br>      echo &quot;❌ artifacts/feature-coverage.html was not generated. Aborting deploy.&quot;<br>      exit 1<br>    fi<br>    echo &quot;✅ feature-coverage.html found ($(wc -c &lt; artifacts/feature-coverage.html) bytes)&quot;</pre><p>Without this, if generate_coverage.py fails silently or writes to the wrong path, the deploy would still proceed — publishing an empty directory, which GitHub Pages then serves as the repository README. This guard turns that silent failure into a loud, obvious CI error with a clear message.</p><h3>A few things I learned along the way</h3><ul><li><strong>The </strong><strong>cache: &#39;pip&#39; trap: <br></strong>When using actions/setup-python with cache: &#39;pip&#39;, GitHub Actions looks for a requirements.txt or pyproject.toml to use as the cache key. If neither exists, the job fails with a confusing error about no matched files. For a single pip install requests, the cache saves maybe two seconds and isn&#39;t worth it. Just drop the option.</li><li><strong>GitHub Pages source setting:<br></strong>After the deploy workflow successfully pushed to the gh-pages branch, the dashboard was still showing the repository README. The reason was that GitHub Pages was configured to serve from the master branch, not gh-pages. You have to go to Settings → Pages → Branch and change it manually. GitHub doesn&#39;t do this automatically even when you start pushing to gh-pages.</li><li><strong>fetch-depth: 0 for path filtering on push events:</strong> <br>The dorny/paths-filter action diffs the current commit against the previous one to determine which files changed. With the default shallow clone, there&#39;s no previous commit to diff against. Adding fetch-depth: 0 to the checkout step gives it the full history it needs.</li><li><strong>force_orphan: true on the Pages deploy:</strong> <br>Without this, every merge that triggers a deploy adds a new commit to the gh-pages branch. After a few months you&#39;d have hundreds of commits that all just say &quot;update coverage report.&quot; Setting force_orphan: true means the branch always has exactly one commit — the latest snapshot. Clean and simple.</li><li><strong>[skip ci] on the deploy commit message:</strong> <br>The deploy job pushes a commit to the gh-pages branch. Without the [skip ci] tag in the commit message, that push can trigger the CI workflow to run again on itself, creating a loop. Adding it to the commit message tells GitHub Actions to ignore that push.</li></ul><h3>The Result</h3><p>My Engineering Manager now has a URL he can bookmark and check anytime. Every time a feature file changes and gets merged, the dashboard updates automatically. No manual reports. No stale spreadsheets. No one needs to remember to do anything.</p><p>The PR comment means the QE team gets immediate coverage feedback during code review, right where they’re already looking, without switching tools. The “missing from CSV” warning catches the most common mistake — adding a feature file and forgetting to register it — before it has a chance to silently skew the numbers.</p><p>And the whole thing runs on tools we already had: GitHub Actions, Python, and GitHub Pages. Nothing new to pay for or maintain.</p><p>It took a few days to get the workflow logic right, but the end result is clean, reliable, and genuinely useful. Sometimes the best dashboards are the ones that just get out of the way and show you what you need.</p><h3>GitHub Repository</h3><p>It’s hard to get real value without looking at a concrete implementation and a working example. To make things clearer, I’ve put together a sample repository you can explore and reference.</p><p><a href="https://github.com/osandadeshan/cucumber-selenium-java-web-automation-demo">https://github.com/osandadeshan/cucumber-selenium-java-web-automation-demo</a></p><p><em>If you’re working with Cucumber and want to set something similar up, the full workflow YAML and Python scripts can be adapted to most Maven or Gradle Java projects with minimal changes. The CSV approach in particular is underrated — it’s boring in the best possible way.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=55b81b789327" width="1" height="1" alt=""><hr><p><a href="https://medium.com/automationmaster/my-engineering-manager-asked-for-a-test-coverage-dashboard-heres-what-i-built-55b81b789327">My Engineering Manager asked for a test coverage dashboard. Here’s what I built</a> was originally published in <a href="https://medium.com/automationmaster">Test Automation Master</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why I Switched from Percy to Playwright for Visual Testing]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/automationmaster/why-i-switched-from-percy-to-playwright-for-visual-testing-7fe3bfa77056?source=rss-5f8c496591b5------2"><img src="https://cdn-images-1.medium.com/max/646/0*FGmUeS4x1IjBYuNO.png" width="646"></a></p><p class="medium-feed-snippet">Zero cost, full control, and automated baseline snapshots management</p><p class="medium-feed-link"><a href="https://medium.com/automationmaster/why-i-switched-from-percy-to-playwright-for-visual-testing-7fe3bfa77056?source=rss-5f8c496591b5------2">Continue reading on Test Automation Master »</a></p></div>]]></description>
            <link>https://medium.com/automationmaster/why-i-switched-from-percy-to-playwright-for-visual-testing-7fe3bfa77056?source=rss-5f8c496591b5------2</link>
            <guid isPermaLink="false">https://medium.com/p/7fe3bfa77056</guid>
            <category><![CDATA[playwright-test]]></category>
            <category><![CDATA[web-automation]]></category>
            <category><![CDATA[test-automation]]></category>
            <category><![CDATA[visual-testing]]></category>
            <category><![CDATA[playwrights]]></category>
            <dc:creator><![CDATA[Osanda Deshan Nimalarathna]]></dc:creator>
            <pubDate>Wed, 31 Dec 2025 15:16:28 GMT</pubDate>
            <atom:updated>2026-01-26T12:06:02.889Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Quick guide to being solid with SOLID principles in Java]]></title>
            <link>https://medium.com/automationmaster/quick-guide-to-being-solid-with-solid-principles-in-java-fd758aa11e08?source=rss-5f8c496591b5------2</link>
            <guid isPermaLink="false">https://medium.com/p/fd758aa11e08</guid>
            <category><![CDATA[best-practices]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[development]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Osanda Deshan Nimalarathna]]></dc:creator>
            <pubDate>Sat, 17 Aug 2024 14:13:51 GMT</pubDate>
            <atom:updated>2024-08-22T05:56:15.257Z</atom:updated>
            <content:encoded><![CDATA[<h4>A beginner’s guide to better Java programming</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NLObPUEEyakUrXpBtqZ7Iw.jpeg" /></figure><h3>Introduction</h3><p>In software development, creating maintainable and scalable code is essential. One way to achieve this is by adhering to SOLID principles. SOLID is an acronym for five design principles that make software designs more understandable, flexible, and maintainable. In this article, I am going to break down each principle with real-world examples using Java.</p><h3>What is SOLID?</h3><p><strong>SOLID</strong> stands for:</p><ol><li><strong>S</strong>ingle Responsibility Principle (SRP)</li><li><strong>O</strong>pen/Closed Principle (OCP)</li><li><strong>L</strong>iskov Substitution Principle (LSP)</li><li><strong>I</strong>nterface Segregation Principle (ISP)</li><li><strong>D</strong>ependency Inversion Principle (DIP)</li></ol><h3>1. Single Responsibility Principle (SRP)</h3><p><strong>Definition:</strong> A class should have only one reason to change. This means that a class should have only one responsibility or job.</p><p><strong>Concept:</strong> Imagine a class that handles multiple unrelated responsibilities. If a change occurs in one responsibility, it might impact the other responsibilities, making the class harder to maintain.</p><p><strong>Detailed Example: </strong>Consider a Report class that handles both report generation and formatting:</p><pre>public class Report {<br>    private String content;<br><br>    public void generateReport() {<br>        // Logic to generate the report content<br>        this.content = &quot;Report Content&quot;;<br>    }<br><br>    public void formatReport() {<br>        // Logic to format the report content<br>        System.out.println(&quot;Formatted Report: &quot; + content);<br>    }<br>}</pre><p><strong>Issue:</strong> The Report class has two responsibilities: generating content and formatting it. If formatting requirements change, you might need to modify the Report class, impacting both responsibilities.</p><p><strong>Solution:</strong> Apply SRP by splitting the responsibilities into different classes:</p><pre>public class Report {<br>    private String content;<br><br>    public void generateContent() {<br>        // Logic to generate the report content<br>        this.content = &quot;Report Content&quot;;<br>    }<br><br>    public String getContent() {<br>        return content;<br>    }<br>}</pre><pre>public class ReportFormatter {<br>    public void format(Report report) {<br>        // Logic to format the report content<br>        System.out.println(&quot;Formatted Report: &quot; + report.getContent());<br>    }<br>}</pre><p><strong>Explanation:</strong> Now, Report is only responsible for content generation, while ReportFormatter handles formatting. This makes each class easier to maintain and change independently.</p><h3>2. Open/Closed Principle (OCP)</h3><p><strong>Definition:</strong> Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.</p><p><strong>Concept:</strong> You should be able to add new functionality without altering existing code. This prevents the risk of introducing bugs when modifying existing, stable code.</p><p><strong>Detailed Example: </strong>Consider a payment processing system that initially supports only credit card payments:</p><pre>public class PaymentProcessor {<br>    public void processCreditCardPayment(double amount) {<br>        // Process credit card payment<br>    }<br>}</pre><p><strong>Issue:</strong> If you want to add support for another payment method (e.g., PayPal), you would need to modify the PaymentProcessor class, which could introduce errors.</p><p><strong>Solution:</strong> Use an interface and separate classes for each payment method:</p><pre>public interface PaymentMethod {<br>    void processPayment(double amount);<br>}</pre><pre>public class CreditCardPayment implements PaymentMethod {<br>    public void processPayment(double amount) {<br>        // Process credit card payment<br>    }<br>}</pre><pre>public class PayPalPayment implements PaymentMethod {<br>    public void processPayment(double amount) {<br>        // Process PayPal payment<br>    }<br>}</pre><pre>public class PaymentProcessor {<br>    private PaymentMethod paymentMethod;<br><br>    public PaymentProcessor(PaymentMethod paymentMethod) {<br>        this.paymentMethod = paymentMethod;<br>    }<br><br>    public void processPayment(double amount) {<br>        paymentMethod.processPayment(amount);<br>    }<br>}</pre><p><strong>Explanation:</strong> PaymentProcessor no longer depends on specific payment methods but rather on the PaymentMethod interface. New payment methods can be added without changing PaymentProcessor.</p><h3>3. Liskov Substitution Principle (LSP)</h3><p><strong>Definition:</strong> Subtypes must be substitutable for their base types without altering the correctness of the program.</p><p><strong>Concept:</strong> If a class is a subtype of another, it should be able to replace the parent class without causing issues. This ensures that the derived class adheres to the behavior expected by the base class.</p><p><strong>Detailed Example: </strong>Consider a base class Bird and a subclass Penguin:</p><pre>public class Bird {<br>    public void fly() {<br>        // Fly implementation<br>    }<br>}</pre><pre>public class Penguin extends Bird {<br>    @Override<br>    public void fly() {<br>        // Penguins can&#39;t fly<br>        throw new UnsupportedOperationException(&quot;Penguins can&#39;t fly&quot;);<br>    }<br>}</pre><p><strong>Issue:</strong> Penguin violates LSP because it cannot substitute Bird without causing issues.</p><p><strong>Solution:</strong> Refactor to ensure that subclasses adhere to the expected behavior:</p><pre>public abstract class Bird {<br>    public abstract void move();<br>}</pre><pre>public class Sparrow extends Bird {<br>    @Override<br>    public void move() {<br>        // Flying implementation<br>    }<br>}</pre><pre>public class Penguin extends Bird {<br>    @Override<br>    public void move() {<br>        // Walking implementation<br>    }<br>}</pre><p><strong>Explanation:</strong> Both Sparrow and Penguin correctly implement move, allowing them to be used interchangeably where Bird is expected.</p><h3>4. Interface Segregation Principle (ISP)</h3><p><strong>Definition:</strong> A class should not be forced to implement interfaces it does not use. Clients should not depend on methods they do not use.</p><p><strong>Concept:</strong> Large interfaces that contain methods unrelated to specific clients should be split into smaller, more specific interfaces. This ensures that implementing classes only need to be concerned with methods that are relevant to them.</p><p><strong>Detailed Example: </strong>Consider a Worker interface with unrelated methods:</p><pre>public interface Worker {<br>    void work();<br>    void eat();<br>}</pre><p><strong>Issue:</strong> A RobotWorker might not need the eat method:</p><pre>public class RobotWorker implements Worker {<br>    public void work() {<br>        // Robot working logic<br>    }<br><br>    public void eat() {<br>        // Unnecessary or throws exception<br>    }<br>}</pre><p><strong>Solution:</strong> Split the interface into more specific ones:</p><pre>public interface Workable {<br>    void work();<br>}</pre><pre>public interface Eatable {<br>    void eat();<br>}</pre><pre>public class HumanWorker implements Workable, Eatable {<br>    public void work() {<br>        // Human working logic<br>    }<br><br>    public void eat() {<br>        // Human eating logic<br>    }<br>}</pre><pre>public class RobotWorker implements Workable {<br>    public void work() {<br>        // Robot working logic<br>    }<br>}</pre><p><strong>Explanation:</strong> Workable and Eatable interfaces are more specific, and RobotWorker implements only the Workable interface, adhering to ISP.</p><h3>5. Dependency Inversion Principle (DIP)</h3><p><strong>Definition:</strong> High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions.</p><p><strong>Concept:</strong> High-level modules should rely on interfaces or abstract classes rather than concrete implementations. This reduces the coupling between different parts of the system and enhances flexibility.</p><p><strong>Detailed Example: </strong>Consider a UserService that directly depends on UserRepository:</p><pre>public class UserRepository {<br>    public void save(User user) {<br>        // Save user logic<br>    }<br>}</pre><pre>public class UserService {<br>    private UserRepository userRepository = new UserRepository();<br><br>    public void register(User user) {<br>        userRepository.save(user);<br>    }<br>}</pre><p><strong>Issue:</strong> UserService is tightly coupled with UserRepository, making it hard to change the repository implementation or to test UserService in isolation.</p><p><strong>Solution:</strong> Use dependency injection and abstractions:</p><pre>public interface UserRepository {<br>    void save(User user);<br>}</pre><pre>public class JdbcUserRepository implements UserRepository {<br>    public void save(User user) {<br>        // Save user logic using JDBC<br>    }<br>}</pre><pre>public class UserService {<br>    private UserRepository userRepository;<br><br>    public UserService(UserRepository userRepository) {<br>        this.userRepository = userRepository;<br>    }<br><br>    public void register(User user) {<br>        userRepository.save(user);<br>    }<br>}</pre><p><strong>Explanation:</strong> UserService depends on the UserRepository interface rather than a concrete implementation. This allows for different implementations of UserRepository and simplifies testing and maintenance.</p><h3>Conclusion</h3><p>SOLID principles needs to be complied when developing software in order to develop code that is reliable and flexible. These SOLID principles Single Responsibility Principle (SRP), Open/Closed Principle (OCP), Liskov Substitution Principle (LSP), Interface Segregation Principle (ISP), and Dependency Inversion Principle (DIP) serve as guidelines to ensure that your code remains clean, maintainable, and scalable.</p><p>By following SRP, you ensure that each class has a single responsibility, which simplifies maintenance and reduces the risk of unintended side effects when changes are made. The OCP encourages you to design systems that can be extended with new functionality without altering existing code, thereby minimizing the risk of introducing bugs. LSP ensures that derived classes can be used interchangeably with their base classes without breaking the functionality, fostering code reliability and consistency. ISP advocates for creating smaller, more specific interfaces, which makes your code more modular and easier to understand. Finally, DIP promotes the use of abstractions rather than concrete implementations, which enhances flexibility and makes your codebase more adaptable to change.</p><p>Incorporating these principles into your Java projects not only helps in building high-quality software but also equips you with best practices that are recognized and valued across the software development industry. By continuously applying SOLID principles, you pave the way for developing software that is easier to test, extend, and maintain ultimately leading to more successful and sustainable software solutions.</p><p>Utilize these principles, practice them regularly, and observe how they transform your approach to software design, making your code more robust and adaptable to future changes.</p><p><strong>Happy Programming !!!</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fd758aa11e08" width="1" height="1" alt=""><hr><p><a href="https://medium.com/automationmaster/quick-guide-to-being-solid-with-solid-principles-in-java-fd758aa11e08">Quick guide to being solid with SOLID principles in Java</a> was originally published in <a href="https://medium.com/automationmaster">Test Automation Master</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Unit Testing Best Practices In React]]></title>
            <link>https://medium.com/automationmaster/react-unit-testing-best-practices-46451ce9b79e?source=rss-5f8c496591b5------2</link>
            <guid isPermaLink="false">https://medium.com/p/46451ce9b79e</guid>
            <category><![CDATA[jest]]></category>
            <category><![CDATA[unit-testing]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[development]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Osanda Deshan Nimalarathna]]></dc:creator>
            <pubDate>Wed, 15 Mar 2023 05:42:03 GMT</pubDate>
            <atom:updated>2023-03-15T05:50:25.346Z</atom:updated>
            <content:encoded><![CDATA[<h4>React application unit testing using Jest</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Odp4AW66gOWIuN9u83WMoA.png" /></figure><h3><strong>What is Unit Testing?</strong></h3><ul><li>Unit testing is a testing method that tests an individual unit of software in isolation.</li><li>Unit testing for React Apps means testing an individual React Component.</li></ul><blockquote><strong><em>“Unit testing is a great discipline, which can lead to 40% — 80% reductions in bug density.</em>” — Eric Elliotte</strong></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*rVYu7hW7MFjEbMdF.png" /></figure><h3><strong>The Test Pyramid</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/466/0*w-yYpZIjydDh7jaD.png" /><figcaption>The test pyramid</figcaption></figure><p>Stick to the pyramid shape to come up with a healthy, fast, and maintainable test suite: Write <strong><em>lots</em></strong> of small and fast <strong><em>unit tests</em></strong>. Write <strong><em>some</em></strong> more <strong><em>coarse-grained tests</em></strong> and <strong><em>very few</em></strong> <strong><em>high-level tests</em></strong> that test your application from end to end. Watch out that you don’t end up with a <a href="https://watirmelon.blog/testing-pyramids/">test ice-cream cone</a> that will be a nightmare to maintain and takes way too long to run.</p><h3><strong>Benefits of Unit Testing</strong></h3><ol><li><strong>Process becomes Agile</strong></li></ol><p>The Agile Testing process is the main advantage of unit testing. When you add more features to the software, it might affect the older designs and you might need to make changes to the old design and code later. This can be expensive and require extra effort. But if you do unit testing, the whole process becomes much faster and easier.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/534/1*rPWPQetB6LI0TUVoYkUdVw.png" /><figcaption>Agile Workflow</figcaption></figure><p><strong>2. Quality of code</strong></p><p>Unit testing significantly improves the quality of the code. It helps developers to identify the smallest defects that can be present in the units before they go for the integration testing.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/378/1*GIZgETmKaa_01w3zApqKMg.png" /></figure><p><strong>3. Facilitates changes</strong></p><p>Refactoring the code or updating the system library becomes much easier when you test each component of the app individually.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/0*NSBqesDjm9bO4PbR.png" /></figure><p><strong>4. Smooth debugging</strong></p><p>The debugging process is very simplified by doing unit testing. If a certain test fails, then only the latest changes that have been made to the code need to be debugged.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/540/0*gMSHPJH4IjJfz8n-.png" /></figure><p><strong>5. Reduction in cost</strong></p><p>When bugs are detected at an early stage, through unit testing, they can be fixed at almost no cost as compared to a later stage, let’s say during production, which can be really expensive.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*EyV7prWzdDivLqx7.png" /></figure><p><strong>6. Act as the best form of documentation</strong></p><p>Unit tests tell you how the original authors intended their code to be used. Read the unit tests and you can learn how the authors consume their own produce.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/0*7ZJwlLg6M-scReuE.png" /></figure><h3><strong>Best Practices</strong></h3><ol><li><strong>Use one test file per component</strong></li></ol><p>Separate different tests into different files to make them well separated, keep the files slim, and make them easily maintainable.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/560/1*u-Oz0QuV4enPi_TarY-FWQ.png" /><figcaption>Separating different tests into different files</figcaption></figure><p><strong>2. Organize your tests with <em>describe</em> and <em>test</em>/<em>it</em></strong></p><p>Use <strong><em>describe</em></strong> to create blocks that group several related tests together and use <strong><em>test</em></strong> or <strong><em>it</em></strong> to execute individual test cases.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/940/1*sB4m_FBUNj13cCYgil-1Sg.png" /><figcaption>Using <strong><em>describe</em></strong> as blocks and <strong><em>test/it</em></strong> as individual test cases</figcaption></figure><p><strong>3. Setup and reset commons in <em>beforeEach</em>/<em>afterEach</em> hooks</strong></p><p>Use <strong><em>beforeEach</em></strong> and <strong><em>afterEach</em></strong> hooks to set up common codes for test cases and reset all mocks after your tests.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/928/1*rzoA-tYSyAgkwfbWuyQbjg.png" /><figcaption>Using <strong><em>beforeEach/afterEach</em></strong> hooks</figcaption></figure><p><strong>4. Use the three A’s pattern</strong></p><p>Arrange/Act/Assert (AAA) is a pattern for organizing unit tests. It breaks tests down into three clear and distinct steps:</p><ul><li><strong>Arrange</strong>: Perform the setup and initialization required for the test.</li><li><strong>Act</strong>: Take action(s) required for the test.</li><li><strong>Assert</strong>: Verify the outcome(s) of the test.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/934/1*uXXe4S1qB7hoHIHLm64rtw.png" /><figcaption>Using 3A’s pattern</figcaption></figure><p><strong>5. Also test what should not happen</strong></p><p>When writing tests, a common practice is to test what a function should do. But you should not only test the obvious but also test the edge cases and negative cases.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/792/1*_R4fT32HvZaSP1uWsTHVyg.png" /><figcaption>Testing the negative cases</figcaption></figure><p><strong>6. Make your tests deterministic</strong></p><p>Your tests should not depend on each other. It goes without saying, but for your tests to be deterministic, you want to ensure that your tests don’t depend on each other. Each test case should be independent of the other and should be able to pass on its own.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/904/1*IDYo-pDLePq4cNtg16RsKw.png" /><figcaption>Using mocking to independent tests</figcaption></figure><p><strong>7. Don’t duplicate implementation logic</strong></p><p>You might copy the same flaws in the logic over to your test suite which means your test suite will pass, but not because it is working correctly. Rather, it contains the same bug as your function. Always test the outcomes, not the implementation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/778/1*KhlxfHopjCz6cb9GulS2oQ.png" /><figcaption>Testing outcomes, not the implementation</figcaption></figure><p><strong>8. Run your tests as part of your deployment</strong></p><p>Run your test suite before each deployment to ensure you didn’t accidentally break any functionality. That way, you can ensure that no bugs are released into a test/production environment for parts of your application that are already covered by tests.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/804/1*hrQytCZ6CrbZC-1p9AUZOA.png" /><figcaption>Deployment life-cycle</figcaption></figure><h3><strong>Demo Repository</strong></h3><p><a href="https://github.com/osandadeshan/react-jest-unit-testing-demo">GitHub - osandadeshan/react-jest-unit-testing-demo: A sample project to demonstrate unit testing for a React project using Jest.</a></p><h3><strong>References</strong></h3><ul><li><a href="https://www.webtips.dev/webtips/jest/jest-best-practices">https://www.webtips.dev/webtips/jest/jest-best-practices</a></li><li><a href="https://martinfowler.com/articles/practical-test-pyramid.html">https://martinfowler.com/articles/practical-test-pyramid.html</a></li><li><a href="https://reactjs.org/docs/testing.html">https://reactjs.org/docs/testing.html</a></li></ul><p><strong>Happy Unit Testing !!!</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=46451ce9b79e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/automationmaster/react-unit-testing-best-practices-46451ce9b79e">Unit Testing Best Practices In React</a> was originally published in <a href="https://medium.com/automationmaster">Test Automation Master</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[No more test flakiness from Selenium locator changes]]></title>
            <link>https://medium.com/automationmaster/no-more-test-flakiness-from-selenium-locator-changes-c25a96d0736d?source=rss-5f8c496591b5------2</link>
            <guid isPermaLink="false">https://medium.com/p/c25a96d0736d</guid>
            <category><![CDATA[healenium]]></category>
            <category><![CDATA[selenium]]></category>
            <category><![CDATA[web-automation]]></category>
            <category><![CDATA[mobile-automation]]></category>
            <category><![CDATA[flaky-tests]]></category>
            <dc:creator><![CDATA[Osanda Deshan Nimalarathna]]></dc:creator>
            <pubDate>Thu, 21 Oct 2021 08:44:20 GMT</pubDate>
            <atom:updated>2021-10-21T12:04:09.579Z</atom:updated>
            <content:encoded><![CDATA[<h4>Heal your web/mobile locators using Healenium</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Rr3TJZf1cfzE4MO-TSJW0A.png" /></figure><h3>What is Healenium?</h3><p><a href="https://healenium.io/">Healenium</a> is an open-source test framework extension that enhances the stability of Selenium-based test cases. It automatically handles the updated web and mobile elements. In practical scenarios, Web and mobile applications are updated constantly in every sprint and that may cause locator changes. Healenium uses a type of machine-learning algorithm to analyze the current page state for changes, handle <strong><em>NoSuchElement </em></strong>test failures, and fix broken tests at runtime by replacing the failed locator with a new value that matches the best and performs an action with the new element successfully. After the test run, Healenium provides detailed reporting with the fixed locators and screenshots. In addition, it supports advanced features like a parallel test run, remote test run, iFrames, actions, selenide integration.</p><p>All of this decreases the time and effort required to write reliable Selenium tests, as well as the number of test cases that fail due to test defects.</p><h3>How Does It Work?</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*6KPrRJrMW4uqQoht.jpg" /></figure><p>Healenium has a client component that connects to test automation frameworks. It has a Tree-comparison dependence in it. An algorithm with self-healing capabilities that examines the current DOM state and generates a new CSS locator by searching for the best subsequence in the current state. It also implements Selenium WebDriver and modifies the findElement method, triggering the Tree-comparing process and initiating self-healing if the NoSuchElement exception is caught.</p><p>Healenium’s backend is a server that uses a PostgreSQL database to execute interactions between the client and the database, which records old and new locator values as well as relevant information such as DOM page, method name, class name, screenshots, and so on.</p><p>There are also Maven and Gradle plugins that generate healing results reports and interact with the backend to obtain information about the healing elements.</p><p>Healenium also offers an <a href="https://www.jetbrains.com/idea/">IntelliJ IDEA</a> plugin for updating the codebase with new location values.</p><h3>Demo Project</h3><h4>Pre-requisites:</h4><ul><li>Clone this GitHub project<br><a href="https://github.com/osandadeshan/healenium-demo">https://github.com/osandadeshan/healenium-demo</a></li><li>Download and install <a href="https://www.jetbrains.com/idea/">JetBrains IntelliJ IDEA</a></li><li>Download and install <a href="https://www.docker.com/products/docker-desktop">Docker Desktop</a></li></ul><h4>Steps to follow:</h4><blockquote><strong>Starting the Healenium Backend</strong></blockquote><p>1. First, make sure Docker is up and running.</p><p>2. Open a Command Prompt or Terminal in the “<strong><em>healenium</em></strong>” directory and execute:</p><pre><strong>docker-compose up -d</strong></pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Kc0a9vrFpoZgcFxB.png" /><figcaption>Running the Healenium backend and database containers</figcaption></figure><p>3. Wait for docker to download the images and finish the setup.</p><p>4. Using the Docker Desktop UI, check that the Healenium backend and database containers are running.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*tjRczPfagGZrknFR.png" /><figcaption>Checking that the Healenium backend and database containers are running</figcaption></figure><p>Or you can execute the below command to check that.</p><pre><strong>docker ps</strong></pre><blockquote><strong>Integrating Healenium in tests</strong></blockquote><p>It’s as simple as writing one line of code to integrate Healenium into your framework. Wrapping the WebDriver in the new SelfHealingDriver is all that’s required.</p><p>But, before that, you have to import,</p><pre><strong>import com.epam.healenium.SelfHealingDriver;</strong></pre><p>Example code:</p><pre>@BeforeMethod<br>public void before() {<br>    WebDriver delegate = new ChromeDriver(); // declare delegate<br>    driver = SelfHealingDriver.create(delegate); // create Self-healing driver<br>    driver.manage().window().maximize();<br>    driver.navigate().to(&quot;<a href="http://automationpractice.com/">http://automationpractice.com/</a>&quot;);<br>}</pre><blockquote><strong>Running the tests</strong></blockquote><p>Run the tests with the proper locators at least once using <strong><em>mvn clean test</em></strong>. After that, we make the following changes to “<strong><em>index.html</em></strong>” in the “<strong><em>src/main/resources/checkout</em></strong>” folder. (You can change any locators as you wish)</p><ul><li>id=“<strong>address</strong>” to id=“<strong>address1</strong>”</li><li>id=“<strong>cc-name</strong>” to id=“<strong>card-name</strong>”</li><li>id=“<strong>cc-number</strong>” to id=“<strong>card-number</strong>”</li><li>id=“<strong>cc-expiration</strong>” to id=“<strong>card-expiration</strong>”</li><li>id=“<strong>cc-cvv</strong>” to id=“<strong>card-cvv</strong>”</li><li>“<strong>Continue to checkout</strong>” to “<strong>Checkout</strong>”</li></ul><p>Normally, this would cause the locators to malfunction because they rely on exact matches. The test will pass because the self-healing driver is used, and it will heal the locators during the runtime.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*0RSdCMdKPO-mRw53.png" /><figcaption>Healing the locators during the runtime</figcaption></figure><p>The locator has been fixed, and the action has been appropriately done, as indicated by the red boxes.</p><p>Let’s say you want to fine-tune Healenium to include a score cap or recovery tries. In such a scenario, create a file called “<strong><em>healenium.properties</em></strong>” and place it in the test resources (“<strong><em>src/test/resources</em></strong>”) directory. The following is the file’s content:</p><pre><strong>recovery-tries = 1<br>score-cap = 0.5<br>heal-enabled = true<br>serverHost = localhost<br>serverPort = 7878</strong></pre><ul><li><strong>recovery-tries</strong> — The number of times the algorithm will try to discover a matched locator.</li><li><strong>score-cap</strong> — The minimum matching score required for the detected locator to be accepted (50% is represented by the number 0.5).</li><li><strong>heal-enabled</strong> — A toggle switch that turns healing on or off. True and false are the accepted values.</li><li><strong>serverHost </strong>— The URL of the Docker Container server that we established while setting up the backend.</li><li><strong>serverPort </strong>— The above-mentioned server’s port</li></ul><p>Run the tests using <strong><em>mvn clean test</em></strong> to generate a new report from the command line. A link to the report generated in the console will appear after a successful test run.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*OixXkYMHr3IqCFkk.png" /><figcaption>Running the tests</figcaption></figure><p>When you open the link in a browser, you’ll get a list of all the locators that have been fixed, along with screenshots of the page where the locators have been fixed. On the right side, there’s a switch to see if the locator has been properly resolved with the correct one.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*FRzgugtct9YmIZGd.png" /><figcaption>Healing Report</figcaption></figure><p>This boilerplate also includes an Allure report as an added feature. After running <strong><em>mvn clean test</em></strong>, run <strong><em>allure serve target/allure-results</em></strong> to generate the Allure report.</p><p>By installing the “<strong>Healenium</strong>” IDE plugin, you can enable the automatic locator updating feature into the IntelliJ IDEA. You can right-click on the locators you want to correct and select Healing Results. You’ll see a little window with a list of fixed locators to choose from, along with their corresponding scores.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/787/0*4RJl5Lbqt8Jh2DgI.png" /><figcaption>Healing the locators using “<strong>Healenium</strong>” IntelliJ IDEA plugin</figcaption></figure><p><strong>Happy Automation !!!</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c25a96d0736d" width="1" height="1" alt=""><hr><p><a href="https://medium.com/automationmaster/no-more-test-flakiness-from-selenium-locator-changes-c25a96d0736d">No more test flakiness from Selenium locator changes</a> was originally published in <a href="https://medium.com/automationmaster">Test Automation Master</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Setting up Automated Code Reviews]]></title>
            <link>https://medium.com/automationmaster/setting-up-automated-code-reviews-f8d370888cc4?source=rss-5f8c496591b5------2</link>
            <guid isPermaLink="false">https://medium.com/p/f8d370888cc4</guid>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[automated-code-review]]></category>
            <category><![CDATA[development]]></category>
            <category><![CDATA[code-review]]></category>
            <category><![CDATA[tools]]></category>
            <dc:creator><![CDATA[Osanda Deshan Nimalarathna]]></dc:creator>
            <pubDate>Sat, 16 Oct 2021 07:26:10 GMT</pubDate>
            <atom:updated>2021-10-22T08:29:02.681Z</atom:updated>
            <content:encoded><![CDATA[<h4>No more hardcore manual reviews ❌</h4><h3>Introduction</h3><h4>What is a Code Review?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*w-hJe2R5ScNrj3cs.png" /></figure><p>“<strong>Code Review</strong>, also known as Peer Code Review, is the act of consciously and systematically convening with one’s fellow programmers to check each other’s code for mistakes and has been repeatedly shown to accelerate and streamline the process of software development like few other practices can.” (From <a href="https://smartbear.com/learn/code-review/what-is-code-review/">SmartBear</a>).</p><h4>The Benefits of Code Reviews</h4><ul><li><strong>Improves code quality:</strong> Code reviews improve code quality by detecting issues before they snowball out of control and ensuring consistent standards. This leads to robust software that is built from components for seamless integration and functionality.</li><li><strong>Supports knowledge transfer:</strong> Source code that is constantly under review allows developers to learn more reliable techniques and best practices.</li><li><strong>Helps teams create better documentation: </strong>Code reviews also help teams to create better documentation, which makes it easier for developers to add features and upgrade existing ones in the future.</li><li><strong>Makes QA testing easier: </strong>Another benefit of maintaining consistent standards is a source code that is easier for specialists and testers to understand. In Quality Assurance (QA) testing, testers will not only have to check the quality of the code, but they will also have to identify issues leading to poor tests. This can lead to persistent, avoidable delays in development due to further testing and reworking.</li></ul><h4>Challenges in Code Reviews</h4><ul><li><strong>Code review happens too late in the development process:</strong> The work has already been done. To rework or to start again could be very time-consuming. The reviewers have a difficult choice: risk the current release while the work is redone, or let it through and suffer the additional technical debt.</li><li><strong>The Wait Time:</strong> This is the biggest issue in code reviews. When the author of the code opens a pull request and marks it ready for review, they need to wait until another person comes along and reviews it. This could be 1 hour after the pull request has been opened (if you are lucky) or it might take a few days or even weeks (if you are not lucky). The wait time is especially painful for us programmers because, after each wait time, the context is lost and needs to be rebuilt again. The longer the wait time the more difficult it is to remember how all the code changes fit together into the shippable feature.</li></ul><h4>Solution for the challenges in Code Reviews</h4><ul><li><strong>Automated code reviews:</strong> It will provide quick feedback for the commits you pushed to the repository.</li></ul><h3>How to integrate automated code reviews into your project?</h3><h4>Required Tool</h4><ul><li><em>Code Inspector GitHub Action</em></li></ul><h4>How does it work?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*cp6WJ-PMhfrT8CP9.png" /><figcaption>Workflow of the Code Inspector</figcaption></figure><h4>Steps to follow</h4><blockquote><strong>Step 1: Create a project in Code Inspector</strong></blockquote><ul><li>Sign up on <a href="https://www.code-inspector.com/">Code Inspector</a>.</li><li>Create a project.</li><li>Install Code Inspector for a repository or multiple repositories you like to have automated code reviews.</li></ul><blockquote><strong>Step 2: Get your Code Inspector API keys</strong></blockquote><ul><li>In your profile, generate API keys.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/483/0*nqJCBsjNHa3kEMFg.png" /><figcaption>Generating API keys</figcaption></figure><ul><li>Once you click on the button, the following window will appear.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/385/0*AziLn7Y-jA1Rx927.png" /><figcaption>Generated API keys</figcaption></figure><blockquote><strong>Step 3: Configure your Code Inspector API keys in your GitHub repository</strong></blockquote><ul><li>You need to add your Code Inspector API keys into GitHub.</li><li>On GitHub, go in your repository settings, click on the secret <em>Secrets</em> (on the right), and create a new secret.</li><li>Create a secret called <strong>CODE_INSPECTOR_ACCESS_KEY</strong> and set it to the value of the access key generated at the previous step.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1023/0*iSZx9q51FJBZgQLb.png" /><figcaption>Creating repository secret key for “<strong>CODE_INSPECTOR_ACCESS_KEY</strong>”</figcaption></figure><ul><li>Create another secret called <strong>CODE_INSPECTOR_SECRET_KEY</strong> and set it to the value of the secret key generated at the previous step.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*7FzznElkxQ7SZAcy.png" /><figcaption>Creating repository secret key for “<strong>CODE_INSPECTOR_SECRET_KEY</strong>”</figcaption></figure><ul><li>Once all secrets have been created, we should have the following secrets generated.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/769/0*1Z8x9ek8mxUGy_jh.png" /><figcaption>Repository secret keys for Code Inspector</figcaption></figure><blockquote><strong>Step 4: Configure the GitHub action</strong></blockquote><p>Create a file <strong>.github/workflows/main.yml</strong> and insert the following content.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bd1baed7c165894482350a600ac680bd/href">https://medium.com/media/bd1baed7c165894482350a600ac680bd/href</a></iframe><p>The following parameters <strong>should <em>NOT</em> be changed</strong>:</p><ul><li><strong>repo_token:</strong> This is how Code Inspector can access your repository</li><li><strong>code_inspector_access_key </strong>and <strong>code_inspector_access_key</strong>: This is how the action can communicate with the Code Inspector analysis engine.</li></ul><p>The following parameters<strong> <em>CAN </em>be changed</strong>:</p><ul><li><strong>min_quality_grade</strong>: The minimum grade your project should have. Valid values are: <strong>EXCELLENT</strong>, <strong>GOOD</strong>, <strong>NEUTRAL</strong>, <strong>WARNING</strong>, <strong>CRITICAL</strong></li><li><strong>min_quality_score</strong>: The minimum code quality scores your project should have. This is a value between <strong>0</strong> and <strong>100</strong>.</li><li><strong>max_defects_rate</strong>: The number of defects per line of code. For example, the value <strong>0.001</strong> means 1 defect per 1000 lines of code.</li><li><strong>max_complex_functions_rate</strong>: The rate of complex functions (E.g. functions with high cyclomatic complexity). For example, a value of <strong>0.5</strong> means that the code should not have more than 50% of functions with high complexity.</li><li><strong>max_long_functions_rate</strong>: The rate of long functions (E.g. functions that are too long to be correctly read by developers). For example, a value of <strong>0.4</strong> means that the code should not have more than 40% of long functions.</li><li><strong>project_name</strong>: The name of the project on <a href="https://www.code-inspector.com/">Code Inspector</a>. This argument is optional: if you set a project name, the analysis engine will use the preferences of this project. Leave blank for not using a project.</li><li><strong>max_timeout_sec</strong>: How many seconds the analysis should come back to you. Default is 600 secconds (10 minutes).</li></ul><blockquote><strong>Step 5: Enjoy the automated code reviews</strong></blockquote><ul><li>Push a new commit and the Code Inspector engine will check if the new code meets your criteria.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gjdVPHamhwzZB03YUoQOww.png" /><figcaption>Code Inspector Audits</figcaption></figure><ul><li>To visualize the details of the result, you can use the <a href="https://frontend.code-inspector.com/">frontend</a>, <a href="https://github.com/codeinspectorio/citool">command-line client</a>, or use directly <a href="https://doc.code-inspector.com/docs/api/">API</a>.</li><li>Code Inspector’s frontend dashboard for the project.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GJV68zGeRdgidxHH6i6D3w.png" /><figcaption>Code Inspector Frontend — Dashboard</figcaption></figure><ul><li>Code Inspector’s frontend analysis for the project.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hdU2VbNa6SiRVYLwmvgT-Q.png" /><figcaption>Code Inspector Frontend — Analysis</figcaption></figure><ul><li>Once we click on the “<strong><em>Violations</em></strong>” showing on a red color chip, we can see the violations on the code.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*H3MhD9zgcDyG-rbjxNB2hg.png" /><figcaption>Code Inspector Frontend — Violations</figcaption></figure><h3>Demo Project</h3><p>GitHub Repo: <a href="https://github.com/osandadeshan/code-quality-demo">https://github.com/osandadeshan/code-quality-demo</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f8d370888cc4" width="1" height="1" alt=""><hr><p><a href="https://medium.com/automationmaster/setting-up-automated-code-reviews-f8d370888cc4">Setting up Automated Code Reviews</a> was originally published in <a href="https://medium.com/automationmaster">Test Automation Master</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Boilerplate projects for Junior Automation Engineers]]></title>
            <link>https://medium.com/automationmaster/boilerplate-projects-for-junior-automation-engineers-5fee9af98151?source=rss-5f8c496591b5------2</link>
            <guid isPermaLink="false">https://medium.com/p/5fee9af98151</guid>
            <category><![CDATA[api-automation]]></category>
            <category><![CDATA[mobile-automation]]></category>
            <category><![CDATA[web-automation]]></category>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[boilerplate]]></category>
            <dc:creator><![CDATA[Osanda Deshan Nimalarathna]]></dc:creator>
            <pubDate>Thu, 07 Oct 2021 03:47:31 GMT</pubDate>
            <atom:updated>2021-10-07T03:47:31.949Z</atom:updated>
            <content:encoded><![CDATA[<h4>Automation Boilerplate Projects</h4><h3>What is a Boilerplate?</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*URd_j_qm0CBxWMne.jpg" /></figure><p>In computer programming, <strong>boilerplate code</strong> or just <strong>boilerplate</strong> are sections of code that are repeated in multiple places with little to no variation. When using languages that are considered <strong><em>verbose</em></strong>, the programmer must write a lot of code to accomplish only minor functionality. Such code is called <strong><em>boilerplate</em></strong>.</p><p>The need for boilerplate can be reduced through high-level mechanisms such as <a href="https://en.wikipedia.org/wiki/Metaprogramming">metaprogramming</a> (which has the computer automatically write the needed boilerplate code or insert it at <a href="https://en.wikipedia.org/wiki/Compile_time">compile time</a>), <a href="https://en.wikipedia.org/wiki/Convention_over_configuration">convention over configuration</a> (which provides good default values, reducing the need to specify program details in every project) and <a href="https://en.wikipedia.org/wiki/Model-driven_engineering">model-driven engineering</a> (which uses models and model-to-code generators, eliminating the need for manual boilerplate code).</p><h3>Web UI Automation Boilerplates</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/643/0*wySHDz05e_dC8XxS.png" /></figure><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c56a416156db2092ca0d39de1d3fe223/href">https://medium.com/media/c56a416156db2092ca0d39de1d3fe223/href</a></iframe><h3>Mobile Automation Boilerplates</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/0*PZGxYMSb8cXpAGpl.png" /></figure><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3ce69976dcb947ad879d78ed4ce1da4b/href">https://medium.com/media/3ce69976dcb947ad879d78ed4ce1da4b/href</a></iframe><h3>API Automation Boilerplates</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*RMsAdxslxOxIWqrv.jpg" /></figure><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3e95e9b6b4d7eb4c59d654d9553d4fdb/href">https://medium.com/media/3e95e9b6b4d7eb4c59d654d9553d4fdb/href</a></iframe><h3>Reporting Boilerplates</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/512/0*hSYdrRb9oTR9EY9R.png" /></figure><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/452e8a87ae5d31e5d4b6ab4f94cbaff2/href">https://medium.com/media/452e8a87ae5d31e5d4b6ab4f94cbaff2/href</a></iframe><p><strong>Happy Automation !!!</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5fee9af98151" width="1" height="1" alt=""><hr><p><a href="https://medium.com/automationmaster/boilerplate-projects-for-junior-automation-engineers-5fee9af98151">Boilerplate projects for Junior Automation Engineers</a> was originally published in <a href="https://medium.com/automationmaster">Test Automation Master</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Good read. Keep it up (Y)]]></title>
            <link>https://osandadeshan.medium.com/good-read-keep-it-up-y-aa777c04c14?source=rss-5f8c496591b5------2</link>
            <guid isPermaLink="false">https://medium.com/p/aa777c04c14</guid>
            <dc:creator><![CDATA[Osanda Deshan Nimalarathna]]></dc:creator>
            <pubDate>Thu, 30 Sep 2021 08:02:30 GMT</pubDate>
            <atom:updated>2021-09-30T08:02:30.528Z</atom:updated>
            <content:encoded><![CDATA[<p>Good read. Keep it up (Y)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=aa777c04c14" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[MaxSoft — TestNG Test Results Analyzer]]></title>
            <link>https://medium.com/testng-test-results-analyzer/maxsoft-testng-test-results-analyzer-1a6687ffebf2?source=rss-5f8c496591b5------2</link>
            <guid isPermaLink="false">https://medium.com/p/1a6687ffebf2</guid>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[testng]]></category>
            <category><![CDATA[automation-testing]]></category>
            <category><![CDATA[reporting-tool]]></category>
            <category><![CDATA[selenium]]></category>
            <dc:creator><![CDATA[Osanda Deshan Nimalarathna]]></dc:creator>
            <pubDate>Sun, 11 Jul 2021 13:04:17 GMT</pubDate>
            <atom:updated>2021-09-27T04:11:15.895Z</atom:updated>
            <content:encoded><![CDATA[<h3>MaxSoft — TestNG Test Results Analyzer</h3><h4>A Java plugin for TestNG to analyze the failed and skipped tests easily in test automation.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*OifwTZmIvOGg59Hi.png" /></figure><h3>Introduction</h3><p>The main reason for developing this plugin is to provide an easy way to analyze the failed and skipped tests in test automation.</p><p>MaxSoft TestNG Test Results Analyzer comes with a built-in failed and skipped tests grouping mechanism. It will generate an Excel file with the failed and skipped tests against the reason. On the same Excel file, the second and third tabs contain the failure and skipped tests grouped under the reason. So it would be easy to identify the tests which failed or skipped due to the same reason.</p><p>Further, this library has built-in Extent reporter as well. So, no need to worry about the HTML report generation for test executions.</p><h3><strong>Features</strong></h3><h4>Test Analysis Report Features</h4><ol><li><strong>Test Summary</strong></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0BCsZ8K3b1LsBR_-OQ8LBg.png" /><figcaption>Test Summary</figcaption></figure><p><strong>2. Failure Analysis</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bnJjNDTpE1ZzdZEzc6cQDw.png" /><figcaption>Failure Analysis — Table View</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*s2J1hxqcRiODbZqkDsXV2w.png" /><figcaption>Failure Analysis — Bar Chart</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jUJFAiFUzUeaTjUgdd1lQw.png" /><figcaption>Failure Analysis — Pie Chart</figcaption></figure><p><strong>3. Skipped Analysis</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9FKlVrWgBrwRDh1jjoYSSA.png" /><figcaption>Skipped Analysis — Table View</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZZv5c_9Gl4C-lhf8gkDj2w.png" /><figcaption>Skipped Analysis — Bar Chart</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NROeBKIoyAMODhI1vU_MdQ.png" /><figcaption>Skipped Analysis — Pie Chart</figcaption></figure><h4>Extent Report Features</h4><ol><li><strong>Dashboard View</strong></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*p69NYt277NjMwJklhT2yOw.png" /><figcaption>Dashboard</figcaption></figure><p><strong>2. Tests View</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*u1Fyhzaqj9iOsIxtxzMuRA.png" /><figcaption>Tests — List View</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HaVCcXDpqgcbxXk90J2B_Q.png" /><figcaption>Tests — Single View</figcaption></figure><p><strong>3. Category View</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QnxLSPfaE4GcVlRr-gt8Qg.png" /><figcaption>Category View</figcaption></figure><p><strong>4. Exception View</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*O2HBhx2YGAPOx6YtrnNerQ.png" /><figcaption>Exception View</figcaption></figure><h3>Advantages</h3><ul><li>Automatically generates the Test Analysis Report after the test execution.</li><li>Automatically generates the Extent Report with screenshots after the test execution.</li><li>Reporter details can be configured through a property file.</li><li>No need to implement classes for Extent reporter or Test Analysis reporter.</li><li>Simple and easy to use.</li></ul><h3>Technologies/Frameworks Used</h3><ul><li>Java</li><li>TestNG</li><li>Apache POI</li><li>Extent Report</li><li>Selenium</li><li>Apache Maven</li></ul><h3>Supported Platforms</h3><ul><li>Windows</li><li>Linux</li><li>Mac OS</li></ul><h3>Supported Language</h3><ul><li>Java</li></ul><h3>Supported Test Runner</h3><ul><li>TestNG</li></ul><h3>How to use</h3><h4>Pre-Requisites:</h4><p>1. Java<br>2. Maven</p><h4>Steps:</h4><ol><li>Add “<strong><em>MaxSoft TestNG Test Results Analyzer</em></strong>” dependency into “<strong><em>pom.xml</em></strong>”.</li></ol><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/57beced8c2d6f92d5b052b7cd283cfe6/href">https://medium.com/media/57beced8c2d6f92d5b052b7cd283cfe6/href</a></iframe><p>2. Create “<strong><em>test-results-analyzer.properties</em></strong>” in “<strong><em>src/main/resources</em></strong>”.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4f6b59865e6b9cc54e2e50606ae97305/href">https://medium.com/media/4f6b59865e6b9cc54e2e50606ae97305/href</a></iframe><p>3. In the test automation code, find the place you are launching the WebDriver.</p><p>4. Pass your WebDriver object to the “<strong><em>setDriver()</em></strong>” method which can be imported from “<strong><em>import static com.maxsoft.testngtestresultsanalyzer.DriverHolder.setDriver</em></strong>”.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2c7c982d00045b6d469c8b633898edd4/href">https://medium.com/media/2c7c982d00045b6d469c8b633898edd4/href</a></iframe><p>5. Update the places where your are using WebDriver object, into “<strong><em>getDriver()</em></strong>” method which can be imported from “<strong><em>import static com.maxsoft.testngtestresultsanalyzer.DriverHolder.getDriver</em></strong>”.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cc0192702b53a735061824ae8bc4d01f/href">https://medium.com/media/cc0192702b53a735061824ae8bc4d01f/href</a></iframe><p>6. An example test. class.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0684b27b4108c5219b31eeeb86abbfd3/href">https://medium.com/media/0684b27b4108c5219b31eeeb86abbfd3/href</a></iframe><p>7. Create the “<strong><em>testng.xml</em></strong>” by adding the “<strong><em>com.maxsoft.testngtestresultsanalyzer.TestAnalyzeReportListener</em></strong>” listener class.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/dcd5d28282c1b69a8b18fd382fc428bd/href">https://medium.com/media/dcd5d28282c1b69a8b18fd382fc428bd/href</a></iframe><p>8. Run the “<strong><em>testng.xml</em></strong>”.</p><p><strong>Happy Automation !!!</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1a6687ffebf2" width="1" height="1" alt=""><hr><p><a href="https://medium.com/testng-test-results-analyzer/maxsoft-testng-test-results-analyzer-1a6687ffebf2">MaxSoft — TestNG Test Results Analyzer</a> was originally published in <a href="https://medium.com/testng-test-results-analyzer">MaxSoft — TestNG Test Results Analyzer</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Be a Leader Everyone Loves to Work With]]></title>
            <link>https://medium.com/automationmaster/how-to-be-a-good-leader-to-your-team-b84c1d6f1185?source=rss-5f8c496591b5------2</link>
            <guid isPermaLink="false">https://medium.com/p/b84c1d6f1185</guid>
            <category><![CDATA[leadership-development]]></category>
            <category><![CDATA[leadership]]></category>
            <category><![CDATA[methodology]]></category>
            <category><![CDATA[leadership-skills]]></category>
            <category><![CDATA[leadership-coaching]]></category>
            <dc:creator><![CDATA[Osanda Deshan Nimalarathna]]></dc:creator>
            <pubDate>Sat, 19 Jun 2021 13:20:44 GMT</pubDate>
            <atom:updated>2021-06-21T12:41:53.733Z</atom:updated>
            <content:encoded><![CDATA[<h4>Leading the team towards the success</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*oVuhM3iCA8Rw_XdQ.jpg" /><figcaption>Leadership</figcaption></figure><p><strong>“The best leaders are the best learners. You have to believe that you (and others) can learn to lead, and that you can become a better leader tomorrow than you are today. Leaders are constant improvement fanatics, and learning is the master skill of leadership.” </strong>– Jim Kouzes, Co-author of The Leadership Challenge and The Student Leadership Challenge</p><p>If you think about an good organization, everyone regardless of their titles or positions is encouraged to <strong>act like a leader.</strong></p><p>Here, I am explaining about <strong>The Five Practices of Exemplary Leadership </strong>to improve your leadership skills.</p><h3>1. Model the Way</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/902/0*AyDZemWvfhBqXA40.jpg" /><figcaption>Model the Way</figcaption></figure><ul><li>Leaders should establish how the team members should be recognized or treated and goals pursued.</li><li>Leaders should be examples for the team members.</li><li>If you think that some task cannot be completed within a given period of time, then you should not give that task to a team member. If you did that, it would be a bad model for the team members and your image will be bad for them.</li></ul><h4>Important points for modeling the way</h4><ol><li>Titles are granted, but your behavior earns you respect.</li><li>Words and deeds must be consistent.</li><li>You must affirm the shared values of the group.</li></ol><h3>2. Inspire a Shared Vision</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*76Pwj2e4FLDtC7Vg.gif" /><figcaption>Inspire a Shared Vision</figcaption></figure><p>Leaders envision the future, see what the organization can become, and get others to see those possibilities.</p><h4>Important points for modeling the way</h4><ol><li>You have to inspire commitment, not command it.</li><li>Visions seen only by leaders are insufficient to create change in a company.</li></ol><h3>3. Challenge the Process</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/0*RgaMUHZrNrRMWckv.png" /><figcaption>Challenge the Process</figcaption></figure><p>Look for innovative ways to improve organizations and accept disappointments as learning opportunities.</p><h4>Important points for modeling the way</h4><ol><li>Leaders venture out; they don’t sit idly by.</li><li>Create a climate where good ideas are supported.</li></ol><h3>4. Enable Others to Act</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/0*nLLLRqy8sxq7Fwz1.jpg" /><figcaption>Enable Others to Act</figcaption></figure><p>Leaders foster collaboration and build spirited teams by actively involving others.</p><h4>Important points for modeling the way</h4><ol><li>Giving power to mentees grants them ownership, making them more capable.</li><li>Seeking opinions of others builds up their capabilities.</li></ol><h3>5. Encourage the Heart</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*XY9Op6X_04XrmOpy.jpg" /><figcaption>Encourage the Heart</figcaption></figure><p>To keep hope and determination alive, leaders recognize contributions that individuals make.</p><h4>Important points for modeling the way</h4><ol><li>Create a culture of celebrating values and victories.</li><li>Celebrations and rituals can carry a group through tough times.</li></ol><blockquote>“<strong>A leader is a dealer in hope.</strong>” <br>Napoleon Bonaparte</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b84c1d6f1185" width="1" height="1" alt=""><hr><p><a href="https://medium.com/automationmaster/how-to-be-a-good-leader-to-your-team-b84c1d6f1185">How to Be a Leader Everyone Loves to Work With</a> was originally published in <a href="https://medium.com/automationmaster">Test Automation Master</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>