<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.3">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2023-10-23T07:32:22+01:00</updated><id>/feed.xml</id><title type="html">Tom Driven Dev</title><subtitle>QA Consultant. Writing code to help developers learn more about their own.</subtitle><author><name>Thomas Shipley</name></author><entry><title type="html">Going Beyond Test Coverage</title><link href="/automated-test/2021/03/11/going-beyond-test-coverage.html" rel="alternate" type="text/html" title="Going Beyond Test Coverage" /><published>2021-03-11T14:31:32+00:00</published><updated>2021-03-11T14:31:32+00:00</updated><id>/automated-test/2021/03/11/going-beyond-test-coverage</id><content type="html" xml:base="/automated-test/2021/03/11/going-beyond-test-coverage.html">&lt;p&gt;Why are you writing automated tests for your project? I hope the answer is to find defects!
Writing tests is not free - someone somewhere must design, develop and maintain them.
All of this is expensive so we must get something out of our investment.&lt;/p&gt;

&lt;p&gt;So how are you proving that your automated tests are valuable and what is the value they deliver?&lt;/p&gt;

&lt;h2 id=&quot;what-is-value-automated-tests-that-always-pass-or-fail&quot;&gt;What is Value? Automated Tests that Always Pass or Fail?&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Automated tests are at there most valuable when they catch defects/bugs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What value do tests that always pass or fail generate? Probably not much - perhaps they even
detract! In my experience, the tests slowly become ignored noise due to a constant pass/fail state which
will either be attributed to a ‘flakiness’ or a ‘reliable’ feature. Who knows if that is the case.&lt;/p&gt;

&lt;p&gt;If your automated tests always pass or fail it is time to review them. An automated test suite that doesn’t catch
any defects isn’t useful. Nor is a test suite that cries wolf all the time. There are multiple reasons why this could be
the case perhaps the test suite isn’t rigorous enough or asks the wrong questions.&lt;/p&gt;

&lt;h2 id=&quot;test-coverage---a-poor-metric-for-value&quot;&gt;Test Coverage - a Poor Metric for Value&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Test coverage doesn’t prove you have valuable tests.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If we agree that valuable tests are those that find defects then tracking test
coverage doesn’t tell us anything about value. Test coverage doesn’t tell us if a test catches defects. 
If I have a project with 100% test coverage does that mean I have a valuable test pack?&lt;/p&gt;

&lt;p&gt;We cannot answer this question. We need to dig deeper.&lt;/p&gt;

&lt;h2 id=&quot;going-beyond-test-coverage&quot;&gt;Going Beyond Test Coverage&lt;/h2&gt;

&lt;p&gt;So if Test Coverage is a poor metric what metrics work well for discovering value?
There are many you could use - I have picked out a few I like.&lt;/p&gt;

&lt;p&gt;To implement these metrics you will probably need to combine some manual effort
with automated reporting. But the results are worth it. You will start to see how valuable your tests are.&lt;/p&gt;

&lt;h3 id=&quot;metric-1-false-negative-rate&quot;&gt;Metric 1: False Negative Rate&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;If you cannot fix a test you must remove it!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Flakiness, flapping tests, unreliable tests - most test suites have them. Tests
which for whatever reason sometimes fail. It could be down to multiple things; environment, poor design,
strict assertions or a timing issue.&lt;/p&gt;

&lt;p&gt;Tracking these failures is very important. You want to see which tests have a high false-negative rate
because these tests are detracting value from your suite. They are noise. Once you identify these tests
you have two options. Fix or remove them.&lt;/p&gt;

&lt;p&gt;Some objections to removal I have come across:&lt;/p&gt;

&lt;h4 id=&quot;tests-an-important-feature&quot;&gt;Tests an Important Feature&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;The unreliable test is important - we need it to test feature X.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;An inconsistent test cannot be relied upon. If the test fails do you have confidence in that failure?
Does your team? It is much better to remove or redesign the test.&lt;/p&gt;

&lt;p&gt;Inconsistent tests will eventually be ignored by the team. You do not want that.&lt;/p&gt;

&lt;h4 id=&quot;test-coverage-will-drop&quot;&gt;Test Coverage will Drop&lt;/h4&gt;

&lt;p&gt;Again test coverage doesn’t tell us anything about value. Test coverage is not as important as valuable
working tests are.&lt;/p&gt;

&lt;h3 id=&quot;metric-2-false-positive-rate&quot;&gt;Metric 2: False Positive Rate&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;It is better to have a test suite that has failures in its execution than a 100% pass rate.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Worse than an unreliable test is a test that always passes so potentially missing defects. Every time
you raise a defect ask the question should the automated tests have caught this? If the answer is yes
and the test exists then note it down. Start to track how many times a test misses a defect.&lt;/p&gt;

&lt;p&gt;If you have tests that are consistently missing defects you have a problem. Again you should redesign
or remove that test. It is giving your team false confidence.&lt;/p&gt;

&lt;h3 id=&quot;metric-3-execution-time&quot;&gt;Metric 3: Execution Time&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;Slow test suite execution slows your team down and detracts value.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;How long do your tests take to run? A test suite is most valuable when it provides fast feedback.
This allows the team to quickly check work and act on the results. If your team has to wait for an
overnight run of tests before release they will be slowed down. When a 
test suite slows down a team in this way it starts to detract value.&lt;/p&gt;

&lt;p&gt;If you see your execution time creeping up then start to think about how you can bring it down. Hopefully,
your tests are designed so they can be executed in any order without issues. If that is the case
perhaps you could execute tests in parallel?&lt;/p&gt;

&lt;h3 id=&quot;metric-4-confirmed-defects-raised&quot;&gt;Metric 4: Confirmed Defects Raised&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;Tests that find defects are creating value.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a simple but powerful metric. Start to record how many defects a test has found. But not just count
also record impact and criticality. Start to get a sense of how valuable the defects your tests find are.
Use this to demonstrate the value or lack of your test suite brings to the project.&lt;/p&gt;

&lt;h3 id=&quot;metric-5-defect-clustering&quot;&gt;Metric 5: Defect Clustering&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;Defects often occur in clusters. Tracking these clusters will help you plan your tests.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every tester has come across defect clustering even if they don’t realise it. Have you
ever been working on something and have a gut feeling, this feature always breaks?
That is defect clustering at work. Where you find a defect you will often find others and they
can be described as a cluster.&lt;/p&gt;

&lt;p&gt;Break your project into clusters. This could be done by feature or perhaps repository. Each time a 
defect is found by your test suite track what cluster it was found in. Start to see where the pattern forms.
Use this to guide where you invest your time in a test suite.&lt;/p&gt;

&lt;p&gt;Perhaps the Shopping Cart seems to always have issues but after tracking defects in clusters you find it is the
Payment logic is the issue. Tracking this way goes one step beyond gut feel.
You can prove that the tests you are planning to write will be valuable because you are using data to target troublesome
areas of your application.&lt;/p&gt;

&lt;h2 id=&quot;writing-tests-and-tracking-coverage-is-not-enough&quot;&gt;Writing Tests and Tracking Coverage is Not Enough&lt;/h2&gt;

&lt;p&gt;It is not enough to just write lots of tests that increase your test coverage metric.
We can do better by focusing on tests that find defects. Finding defects is what we want from our test suites after all!&lt;/p&gt;

&lt;p&gt;Tracking defects found, the impact of those defects and where they appear you can start to plan tests based on
data and provide more value to your team.&lt;/p&gt;</content><author><name>Thomas Shipley</name></author><category term="automated-test" /><category term="metrics" /><category term="automated tests" /><summary type="html">Why are you writing automated tests for your project? I hope the answer is to find defects! Writing tests is not free - someone somewhere must design, develop and maintain them. All of this is expensive so we must get something out of our investment.</summary></entry><entry><title type="html">Ready for Test - a Symptom of a Poor Quality Culture</title><link href="/leadership/2021/01/09/ready-for-test-a-symptom-of-a-poor-quality-culture.html" rel="alternate" type="text/html" title="Ready for Test - a Symptom of a Poor Quality Culture" /><published>2021-01-09T11:31:32+00:00</published><updated>2021-01-09T11:31:32+00:00</updated><id>/leadership/2021/01/09/ready-for-test-a-symptom-of-a-poor-quality-culture</id><content type="html" xml:base="/leadership/2021/01/09/ready-for-test-a-symptom-of-a-poor-quality-culture.html">&lt;p&gt;The Ready for Test column on your JIRA/Agile/Kanban/Whatever process feels safe, doesn’t it?
It is a well-known column and on the surface seems to follow nicely with how tickets are worked on.
There is a bit of elaboration, then some code is written (hopefully reviewed) and finally
we can move it into QA where an independent set of eyes can take a look at it. But doesn’t it
all sound a little less Agile and a bit more Waterfall?&lt;/p&gt;

&lt;p&gt;Ideas such as Shift Left, Continuous Integration and DevOps are increasingly popular. Their popularity
stems from early feedback, sharing knowledge and ownership between team members. Yet Agile software
teams continue to treat QA concerns as a separate stage owned by different people. All the benefits of
the Agile ways of working above give us are lost. QA team members provide feedback after the task,
hoarding knowledge and being passed ownership of quality.&lt;/p&gt;

&lt;p&gt;In this post, I want to convince you that in a lot of cases Ready for Test, In QA and other quality
gates do more harm than good. They contribute to a culture of separation between QAs and other team
members. This separation causes quality to decrease.&lt;/p&gt;

&lt;h2 id=&quot;quality-is-the-concern-of-all&quot;&gt;Quality is the Concern of All&lt;/h2&gt;

&lt;p&gt;Let us start with the basics. Everyone on the team has a responsibility to deliver a quality product.
That is not something specific to our industry but is true in near all industries. A well-performing team
works together and helps each other to achieve a goal whether that is a successful Sprint in IT or
on the Athletic track.&lt;/p&gt;

&lt;p&gt;So here is the first issue with Ready for Test. If we all have a responsibility to deliver good work then why
hasn’t the work been ready for testing from the first step? And why should a specific person check that work?&lt;/p&gt;

&lt;p&gt;Testing is more than checking the nuts and bolts fit together. It is also discovering if those nuts and bolts
should be put together and if it is being done in the right way.&lt;/p&gt;

&lt;h2 id=&quot;testing-early-and-continuously&quot;&gt;Testing Early and Continuously&lt;/h2&gt;

&lt;p&gt;This brings us onto early testing. How can we question design and method early on before we as a team
test functionality? As development continues the approach will change, how can we verify this change?&lt;/p&gt;

&lt;h3 id=&quot;three-amigos&quot;&gt;Three Amigos&lt;/h3&gt;

&lt;p&gt;Get some people in a room - canonically a developer, QA and BA/Product Owner. At the start of a piece of work
discuss the aims and the constraints. Talk about the concerns of the ticket be it testing, business or user ones.
Note down on the ticket any important points.&lt;/p&gt;

&lt;p&gt;You are testing assumptions and the shared understanding of the work. Clearing up misunderstanding early on
saves time later on fixing defects and bugs.&lt;/p&gt;

&lt;h3 id=&quot;pairing&quot;&gt;Pairing&lt;/h3&gt;

&lt;p&gt;Once upon a time, I was sat in a retro with my team. I wanted developers on the team to be more available for pairing
and working on testing tasks. Some of the developers weren’t too happy. They wanted to focus on feature work. Not
“QA” work.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“If we are meant to pair on Test tickets then that means you should be pairing on Dev tickets?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Yes!&lt;/strong&gt; Pairing is a great way to test things early and importantly should work both ways.&lt;/p&gt;

&lt;p&gt;QAs should pair with developers on feature work asking questions about implementation and improving there understanding.
Equally, Developers should be doing the same. We don’t want silos in software development. We want knowledge to be spread
across the team so if one person leaves its not a mad dash to take on knowledge transfer tasks.&lt;/p&gt;

&lt;h3 id=&quot;discovery--spike-tickets&quot;&gt;Discovery / Spike Tickets&lt;/h3&gt;

&lt;p&gt;Sometimes the team doesn’t know enough about a problem to deliver on the shared promise of quality. In these cases, someone
will suggest a Spike or Discovery ticket. A timeboxed assigned task to someone to investigate and return with more
information for the team so an informed decision can be made.&lt;/p&gt;

&lt;p&gt;These types of tasks are all about testing. Testing an idea, evaluating options and returning a conclusion. They are also
a natural fit for Pairing. Devs and QAs should work on these spikes to make sure the correct questions are being asked,
the right options are evaluated and results are presented from a multifaceted view.&lt;/p&gt;

&lt;h2 id=&quot;manual-and-automated-testing---a-separate-stage&quot;&gt;Manual and Automated Testing - a Separate Stage?&lt;/h2&gt;

&lt;p&gt;If everyone owns the quality of delivery then everyone owns the verification of that quality right? You cannot have shared
ownership of something if only a handful of people verify it. The teams should as a whole be questioning if a suitable
level of quality has been achieved before release.&lt;/p&gt;

&lt;p&gt;This brings me to testing. A developer doesn’t need a QA to test anything. There is evidence of this already - when the
developers on a team write unit tests. This task is managed easily. There is no reason why a developer working on a task
cannot also write some functional automated tests. Perhaps they could also do a manual check if required.&lt;/p&gt;

&lt;p&gt;I can hear the pushback through my screen. &lt;em&gt;“I shouldn’t test my own work - separation helps find defects.”&lt;/em&gt; I agree. But that
separation doesn’t need to be from a QA - it certainly doesn’t need to be a separate stage. It should already be happening.
&lt;strong&gt;Quality is a feature, not an afterthought.&lt;/strong&gt; Anyone can pair on testing activities and they should be doing so early and throughout
the progress of a ticket. Pairing, Three Amigos, Spikes will all allow you to do this.&lt;/p&gt;

&lt;h2 id=&quot;there-is-no-ready-for-test---it-already-is&quot;&gt;There is no Ready for Test - It Already is&lt;/h2&gt;

&lt;p&gt;We have seen techniques to allow us to test early and continuously. If we have been utilising them then what is left? Not much.
Testing has been constant, a pair of team members have been working together on a ticket which was well understood because we
either held a Three Amigos session to avoid misunderstandings or a Spike.&lt;/p&gt;

&lt;p&gt;Ok, there might need to be some final checks driven by how much risk is associated with the work. That is what Demo sessions are for.
Demo to your squad, your team, your product owner. A bit nervous before the demo? Grab a team member and demo it to just them -
if it makes you feel better to call it pairing!&lt;/p&gt;

&lt;h2 id=&quot;faq&quot;&gt;FAQ&lt;/h2&gt;

&lt;h3 id=&quot;so-what-is-the-role-of-a-qa&quot;&gt;So What is the Role of a QA?&lt;/h3&gt;

&lt;p&gt;Ok, I have now talked myself out of a job it seems. Sometimes - but more often not.&lt;/p&gt;

&lt;p&gt;QAs on a team are typically outnumbered by other team members. They cannot be involved in everything
and shouldn’t be. Their time is better spent shepherding the team towards shared ownership of quality and
ensuring that collective responsibility is established. Someways this can be done:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Pairing with Developers&lt;/li&gt;
  &lt;li&gt;Doing Discovery work to Enable Better Testing&lt;/li&gt;
  &lt;li&gt;Setting up Test Infrastructure to make it easier for others to Test&lt;/li&gt;
  &lt;li&gt;Liaising with Testers in other teams&lt;/li&gt;
  &lt;li&gt;Reviewing user feedback. Bringing that information to the team&lt;/li&gt;
  &lt;li&gt;Running Three Amigos/Retro/Standup sessions&lt;/li&gt;
  &lt;li&gt;Testing high-risk features where extra reassurance is needed&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;where-should-i-put-testing-tasks-on-the-board&quot;&gt;Where should I put Testing Tasks on the Board?&lt;/h3&gt;

&lt;p&gt;Treat these tickets like any other ticket. Ready for development, In Progress. Testing tasks don’t need a special
column all of there own. It only serves to encourage testing to be the responsibility of a small subset of
the team.&lt;/p&gt;</content><author><name>Thomas Shipley</name></author><category term="leadership" /><category term="leadership" /><category term="team-culture" /><category term="soft-skills" /><summary type="html">The Ready for Test column on your JIRA/Agile/Kanban/Whatever process feels safe, doesn’t it? It is a well-known column and on the surface seems to follow nicely with how tickets are worked on. There is a bit of elaboration, then some code is written (hopefully reviewed) and finally we can move it into QA where an independent set of eyes can take a look at it. But doesn’t it all sound a little less Agile and a bit more Waterfall?</summary></entry><entry><title type="html">Should I Write Consumer-Driven Contract Tests for Services I Own?</title><link href="/pact/consumer%20driven%20contract%20testing/2020/07/14/should-I-write-consumer-driven-contract-tests-for-services-I-own.html" rel="alternate" type="text/html" title="Should I Write Consumer-Driven Contract Tests for Services I Own?" /><published>2020-07-14T12:31:32+01:00</published><updated>2020-07-14T12:31:32+01:00</updated><id>/pact/consumer%20driven%20contract%20testing/2020/07/14/should-I-write-consumer-driven-contract-tests-for-services-I-own</id><content type="html" xml:base="/pact/consumer%20driven%20contract%20testing/2020/07/14/should-I-write-consumer-driven-contract-tests-for-services-I-own.html">&lt;p&gt;The &lt;a href=&quot;https://www.ministryoftesting.com/slack_invite&quot;&gt;Ministry of Testing Slack Channel&lt;/a&gt; is free to join and a great place to ask questions of the testing community. A (paraphrased) question I was asked recently:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If I own two services which integrate - do I need to set up a consumer-driven (pact) contract test between them? Perhaps I can use a simple integration test instead?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is a question I have come across a few times now when working with teams.&lt;/p&gt;

&lt;h2 id=&quot;tldr-yes-you-should&quot;&gt;TL;DR; Yes you Should&lt;/h2&gt;

&lt;p&gt;Just because you own both services doesn’t mean the relationship between them stops existing. A Consumer-Driven Contract Test will allow you to keep tabs on that relationship and catch any drift between the two services without expensive, slow and hard to maintain integration tests.&lt;/p&gt;

&lt;h2 id=&quot;a-quick-recap---what-is-a-consumer-driven-contract-test-cdct&quot;&gt;A Quick Recap - What is a Consumer-Driven Contract Test (CDCT)?&lt;/h2&gt;

&lt;p&gt;I have written before about &lt;a href=&quot;https://tomdriven.dev/.net%20core/c%23/contract%20testing/pact/test/2018/03/13/contract-testing-with-pact-in-net-core.html&quot;&gt;what a CDCT is&lt;/a&gt; but as a quick recap. A CDCT is a contract test where your consumer defines the API contract. The inverse is a more typical contract test relying on the API provider (developer) to define the contract.&lt;/p&gt;

&lt;p&gt;It is preferable to have the consumer define the contract. The resultant contract will more accurately reflect API usage and is less likely to go out of date as the contract is generated by the consumer’s test suite.&lt;/p&gt;

&lt;p&gt;I like to use &lt;a href=&quot;https://pact.io/&quot;&gt;Pact&lt;/a&gt; as a framework to write these tests but there are other options like &lt;a href=&quot;https://saucelabs.com/blog/intro-to-contract-testing-getting-started-with-postman&quot;&gt;Postman&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So that is what a CDCT is. But what is the purpose?&lt;/p&gt;

&lt;h3 id=&quot;testing-relationships---the-key-to-a-successful-system&quot;&gt;Testing Relationships - The Key to a Successful System&lt;/h3&gt;

&lt;p&gt;Whether we use integration, end to end or CDCT techniques they are all aiming to do the same thing - test relationships. When we write and execute these tests teams and individuals say things like:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We are checking the system &lt;em&gt;hangs together&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What is meant by the phrase &lt;em&gt;hangs together&lt;/em&gt; is the system communicates well together. The Basket service can &lt;em&gt;speak&lt;/em&gt; to the Payments service. The Authorisation service &lt;em&gt;verifies&lt;/em&gt; that only certain users in the Accounts service can access a resource.&lt;/p&gt;

&lt;p&gt;These are relationships and they are critical, without them, you don’t have a system. This is more prevalent in a microservice architecture where the number of relationships increases.&lt;/p&gt;

&lt;h2 id=&quot;so-back-to-the-question-why-integration-tests-cant-replace-cdcts&quot;&gt;So Back to the Question. Why Integration Tests Can’t Replace CDCTs?&lt;/h2&gt;

&lt;p&gt;The original question comes in two parts:&lt;/p&gt;

&lt;h3 id=&quot;do-i-need-to-use-a-cdct-if-i-own-both-services&quot;&gt;Do I need to use a CDCT if I own both services?&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The relationship between your two services still exists when you own the development of them both. The question hints that maybe because both sides of the relationship are owned by the same team that the contract between both services will be easily be maintained - this is not my personal experience.&lt;/p&gt;

&lt;p&gt;Imagine a team that owns multiple small well-designed services that all communicate with each other. Like all teams, you are subject to changing requirements and priorities. You spend some time working on one service and then switch to the next. In this scenario, it is very easy for the relationship between just two services to drift.&lt;/p&gt;

&lt;p&gt;You or a colleague makes a change in one service which changes to the format of an attribute importantly - let’s say a date field (they are tedious…) well that is easily missed - it is subtle. If you had a CDCT this would be picked up immediately. With an integration test, it &lt;em&gt;might&lt;/em&gt; be picked up if you designed the test to check that.&lt;/p&gt;

&lt;h3 id=&quot;can-an-integration-test-replace-a-cdct&quot;&gt;Can an Integration Test Replace a CDCT?&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;No&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Integration tests can test relationships and CDCTs are not suitable all the time. For example, an external service which will not work on creating CDCTs with you. But in most cases, integration tests are a poor choice for testing relationships - because they are…&lt;/p&gt;

&lt;h4 id=&quot;slow&quot;&gt;Slow&lt;/h4&gt;

&lt;p&gt;Either because they are waiting for an environment to be spun up or some other downstream system. A CDCT doesn’t wait for any system. It is a decoupled approach to relationship testing meaning you get faster feedback and don’t need to maintain an integration testing environment.&lt;/p&gt;

&lt;h4 id=&quot;brittle&quot;&gt;Brittle&lt;/h4&gt;

&lt;p&gt;The previous example of a date change shows how brittle an integration test can be. Unless your integration test had a specific assert of the date format the issue won’t be picked up. Now I can imagine you saying:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;A well-designed integration test will have a format check.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Maybe. But maybe it just checks the date can be &lt;em&gt;parsed&lt;/em&gt; rather than a specific format? A CDCT will pick up the format change even if you didn’t specifically write an assert for it (unless you decided to accept any string… then it is on you!).&lt;/p&gt;

&lt;p&gt;Integration tests also rely on a specific environment. Either a long-running or temporarily generated environment which inevitably breaks over time (OS &amp;amp; Package updates, config changes) so has to be maintained. CDCT don’t require this. Instead sharing a contract file to support decoupling.&lt;/p&gt;

&lt;h2 id=&quot;consumer-driven-contract-tests--integration-tests&quot;&gt;Consumer-Driven Contract Tests &amp;gt; Integration Tests&lt;/h2&gt;

&lt;p&gt;Integration tests have their place. Sometimes it will be impractical to set up a CDCT because you haven’t got the required cooperation.&lt;/p&gt;

&lt;p&gt;But in most cases, I would recommend using a CDCT over an integration test. This advice doesn’t change if you own both sides of the relationship. The same issues as before exist. If anything it makes it easier for you to adopt CDCTs as you don’t need to convince another team!&lt;/p&gt;</content><author><name>Thomas Shipley</name></author><category term="pact" /><category term="consumer driven contract testing" /><category term="pact" /><category term="consumer driven contract testing" /><summary type="html">The Ministry of Testing Slack Channel is free to join and a great place to ask questions of the testing community. A (paraphrased) question I was asked recently:</summary></entry><entry><title type="html">Selling Teams on Change As a QA</title><link href="/change/soft%20skills/2020/03/02/selling-teams-on-change-as-a-qa.html" rel="alternate" type="text/html" title="Selling Teams on Change As a QA" /><published>2020-03-02T14:21:31+00:00</published><updated>2020-03-02T14:21:31+00:00</updated><id>/change/soft%20skills/2020/03/02/selling-teams-on-change-as-a-qa</id><content type="html" xml:base="/change/soft%20skills/2020/03/02/selling-teams-on-change-as-a-qa.html">&lt;h2 id=&quot;how-do-i-convince-my-team-to-do-this&quot;&gt;How Do I Convince My Team to Do This?&lt;/h2&gt;
&lt;p&gt;I was asked this question after presenting my &lt;a href=&quot;https://tomdriven.dev/events/&quot;&gt;talk on Consumer-Driven Contract Tests&lt;/a&gt; at London Tester Gathering. It is a great question. People generally don’t like change and even less so when the concept is unfamiliar.&lt;/p&gt;

&lt;p&gt;The question went on to ask (paraphrasing) - &lt;strong&gt;“How do I approach the Delivery Leads about getting the time to do this?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;That is your first mistake!&lt;/em&gt; Delivery Leads, Tech Leads, Product Owners, maybe even QA Managers have different goals to you the QA in the team. Yes we all hopefully want to deliver quality software but approach it in different ways.&lt;/p&gt;

&lt;h2 id=&quot;the-two-objectives-of-a-software-project&quot;&gt;The Two Objectives of a Software Project&lt;/h2&gt;
&lt;p&gt;There are ultimately two objectives of a software project &lt;strong&gt;deliver software&lt;/strong&gt; that is of sufficient &lt;strong&gt;quality&lt;/strong&gt;. The contentious point being &lt;em&gt;quality&lt;/em&gt;. What you as a QA consider as ready to release will be different from that of a Lead type role and that is ok.&lt;/p&gt;

&lt;p&gt;The primary role of a &lt;strong&gt;QA&lt;/strong&gt; in a team is to champion &lt;em&gt;quality&lt;/em&gt;. The primary role of a &lt;strong&gt;Lead&lt;/strong&gt; is to &lt;em&gt;deliver&lt;/em&gt;. Of course, both roles care about each point but if you had to pick that is how it typically falls.&lt;/p&gt;

&lt;p&gt;So when you ask your Lead &lt;strong&gt;Can I have time to investigate this new Idea?&lt;/strong&gt; they naturally might push back - worried about delivery timescales.&lt;/p&gt;

&lt;h2 id=&quot;the-secret---dont-ask&quot;&gt;The Secret - Don’t Ask&lt;/h2&gt;
&lt;p&gt;The best advice I have ever been given was the old adage:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;It is easier to ask forgiveness than seek permission. - &lt;a href=&quot;https://quoteinvestigator.com/2018/06/19/forgive/&quot;&gt;Grace Hopper…&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Guess what - it is true! So below is my approach based on this advice on convincing people of a new idea.&lt;/p&gt;

&lt;h3 id=&quot;disclaimer&quot;&gt;Disclaimer&lt;/h3&gt;
&lt;p&gt;This is my own personal approach and not all people and companies are the same. Don’t just blindly follow what some stranger says on the internet. You will be taking time away from delivery following this approach so try not to do it around important deadlines. Use your own judgement.&lt;/p&gt;

&lt;p&gt;That said you should definitely give this approach a go. You as a QA are the champion of quality so should try new ideas in defending it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you find yourself in a place where you are so micromanaged that you cannot have any little side projects in work consider moving on. I have worked in places like that and generally found they are not worth sticking around.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;step-1---talk-about-your-idea-with-your-colleagues&quot;&gt;Step 1 - Talk About Your Idea with your Colleagues&lt;/h2&gt;
&lt;p&gt;My most recent example of this approach is based on my work at John Lewis with Equal Experts. I wanted to introduce Consumer-Driven Contract Tests - but it was met with some skepticism.&lt;/p&gt;

&lt;p&gt;So firstly, speak to others who might agree it is a good idea. Discuss the idea with them - ask lots of questions see if it is as good as you think. If even the people you thought would agree do not then think about why. Maybe this is not a good idea.&lt;/p&gt;

&lt;p&gt;Try a different angle and refine until someone agrees. You can move onto step two without agreement but the risk of it not working out increases.&lt;/p&gt;

&lt;h2 id=&quot;step-2---create-a-very-small-and-simple-proof-of-concept&quot;&gt;Step 2 - Create a Very Small and Simple Proof of Concept&lt;/h2&gt;
&lt;p&gt;Now you have found some agreement work with it to create a simple working solution to at least part of your problem.&lt;/p&gt;

&lt;p&gt;In John Lewis, it was a QA in another team. We worked together to create a very simple Consumer-Driven Contract Test and set up a simple &lt;a href=&quot;https://github.com/pact-foundation/pact_broker&quot;&gt;Broker&lt;/a&gt; to go with it.&lt;/p&gt;

&lt;p&gt;Now you have more than just an idea. You have something you can show people as well. This is ideal for the next stage. It frames the discussion and will help people get over the psychological barrier of taking the first step.&lt;/p&gt;

&lt;h2 id=&quot;step-3---showcase-your-work&quot;&gt;Step 3 - Showcase Your Work&lt;/h2&gt;
&lt;p&gt;Demo your simple proof of concept to your teams. If you have a related community (such as a weekly QA catch up) demo it there too. Speak to people about it. Get feedback.&lt;/p&gt;

&lt;p&gt;As you get the feedback you may find that other people want to be involved. If you do great! This likely means you are solving a problem others have.&lt;/p&gt;

&lt;p&gt;In John Lewis after some demo and promotional work, the idea gained momentum. Now there is a post on the &lt;a href=&quot;https://medium.com/john-lewis-software-engineering/consumer-driven-contract-testing-a-scalable-testing-strategy-for-microservices-3f2b09f99ed1&quot;&gt;John Lewis Engineering Blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After doing all this showcase work you should hopefully have a proven out idea to take to your lead.&lt;/p&gt;

&lt;h2 id=&quot;step-4---speak-to-your-leads&quot;&gt;Step 4 - Speak to Your Lead(s)&lt;/h2&gt;
&lt;p&gt;Now is the time to ask your Lead for time to investigate this idea further. Show them the proof of concept and how the idea has gathered momentum after you demoed it to your fellow QAs or Developers.&lt;/p&gt;

&lt;p&gt;They will of course still be thinking about delivery. But it is a lot harder to dismiss an idea with momentum behind it.&lt;/p&gt;

&lt;h2 id=&quot;but-it-might-not-work-out&quot;&gt;But it Might Not Work Out&lt;/h2&gt;

&lt;p&gt;At any of the stages above your idea may not work out. Some time was spent but it didn’t help with delivery or quality. That happens in software all the time - not all ideas are winners. But you probably learnt about:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Critical analysis&lt;/li&gt;
  &lt;li&gt;Technologies&lt;/li&gt;
  &lt;li&gt;Testing concepts&lt;/li&gt;
  &lt;li&gt;Presenting to an individual or group&lt;/li&gt;
  &lt;li&gt;Managing expectations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That seems worth taking the risk to me. But if all else fails ask for forgiveness!&lt;/p&gt;</content><author><name>Thomas Shipley</name></author><category term="change" /><category term="soft skills" /><category term="change" /><category term="soft skills" /><summary type="html">How Do I Convince My Team to Do This? I was asked this question after presenting my talk on Consumer-Driven Contract Tests at London Tester Gathering. It is a great question. People generally don’t like change and even less so when the concept is unfamiliar.</summary></entry><entry><title type="html">QA Interview Tip - Everything is Not Awesome</title><link href="/interviewing/2020/02/12/interview-you-dont-like-everything.html" rel="alternate" type="text/html" title="QA Interview Tip - Everything is Not Awesome" /><published>2020-02-12T08:18:32+00:00</published><updated>2020-02-12T08:18:32+00:00</updated><id>/interviewing/2020/02/12/interview-you-dont-like-everything</id><content type="html" xml:base="/interviewing/2020/02/12/interview-you-dont-like-everything.html">&lt;h2 id=&quot;the-lego-movie-got-it-wrong-and-that-is-ok&quot;&gt;The Lego Movie Got It Wrong and That is OK&lt;/h2&gt;

&lt;p&gt;Everything is &lt;em&gt;not&lt;/em&gt; awesome (despite the catchy &lt;a href=&quot;https://www.youtube.com/watch?v=9cQgQIMlwWw&quot;&gt;song&lt;/a&gt;) and you don’t like every QA tool or technology you have ever worked with and neither do I, at least not completely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And that is ok.&lt;/strong&gt; I am not going to judge you in an interview for saying you don’t like a certain tool, tech or technique either partially or completely. In fact, as an interviewer, I often ask interviewees what QA thing they don’t like. I am suspicious when they say nothing (unless you are inexperienced). It is important to question the body of knowledge we have as a community and to constantly evaluate it.&lt;/p&gt;

&lt;p&gt;Without questioning what we are doing and why we all risk becoming cargo cult QAs. I want to work with people who are looking for the best way of doing things and not because that is how they have always been done.&lt;/p&gt;

&lt;h3 id=&quot;a-caveat-tell-me-why&quot;&gt;A Caveat… Tell Me Why&lt;/h3&gt;

&lt;p&gt;Please if you don’t like something then tell me why. Just saying I dislike BDD or Generic Unit Test Framework with no follow up doesn’t show me your critical thinking skills. If you don’t like something say why you don’t. It might be buggy, it could be lazily implemented or perhaps it gets in your way.&lt;/p&gt;

&lt;h2 id=&quot;things-i-dont-like-in-qa&quot;&gt;Things I Don’t Like in QA&lt;/h2&gt;

&lt;p&gt;In the spirit of this post here are some things I don’t like in the QA world. If you are ever in an interview with me feel free to ask about them. They are all concepts rather than technology for no particular reason.&lt;/p&gt;

&lt;h3 id=&quot;the-test-pyramid&quot;&gt;The Test Pyramid&lt;/h3&gt;

&lt;p&gt;Simplistic, misused and rarely implemented correctly. The key idea behind the Test Pyramid in fairness is a good one - let’s have most of our tests as tightly scoped as possible. So instead of lots of end to end tests, we have lots of little focused ones instead.&lt;/p&gt;

&lt;p&gt;The problem, however, is the pyramid is often supported dogmatically in my experience and rarely implemented well. Instead, teams often try to build up testing in the layers of pyramid rather than thinking about risk what is the highest priority. This, in the end, makes teams feel bad that they never hit the mythical perfect pyramid shape.&lt;/p&gt;

&lt;h4 id=&quot;read-more&quot;&gt;Read More&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/@fistsOfReason/testing-is-good-pyramids-are-bad-ice-cream-cones-are-the-worst-ad94b9b2f05f&quot;&gt;Testing is Good. Pyramids are Bad. Ice Cream Cones are the Worst&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;integration-tests&quot;&gt;Integration Tests&lt;/h3&gt;

&lt;p&gt;I can see the appeal of Integration Tests. Your system is made up of many moving parts and you want to check that they work together. But you don’t want to set up the whole system as it would take too long and is too expensive so you do it in chunks.&lt;/p&gt;

&lt;p&gt;The problem with this is the testing in chunks is still expensive and takes too long. Orchestrating your chunks together on an environment can be painful. Setting up test data which avoids conflicts between tests can be worse.&lt;/p&gt;

&lt;p&gt;If your system is made up of many services then I prefer &lt;em&gt;consumer driven contract tests&lt;/em&gt; with only a &lt;strong&gt;very small&lt;/strong&gt; amount of integration/end to end tests. The small amount of integration/end to end tests that are left act as a sanity check of the very basics of your system. The consumer-driven contract tests verify all the little relationships between the different parts.&lt;/p&gt;

&lt;h4 id=&quot;read-more-1&quot;&gt;Read More&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html&quot;&gt;Just Say No to More End-to-End Tests&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.thecodewhisperer.com/permalink/integrated-tests-are-a-scam&quot;&gt;Integrated Tests Are A Scam&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://martinfowler.com/articles/consumerDrivenContracts.html&quot;&gt;Consumer Driven Contracts: A Service Evolution Pattern&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://pact.io/&quot;&gt;Pact.io&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bdd-everywhere&quot;&gt;BDD Everywhere&lt;/h3&gt;

&lt;p&gt;You have a suite of Integration or End to End tests and they are written with Selenium. Having read some testing blogs you now use a BDD framework on top like Cucumber because it allows developers and business people alike to read tests in English like language. If your team actually does read the cucumber specs to help with understanding then I don’t have a problem with the technique.&lt;/p&gt;

&lt;p&gt;A lot of places don’t do that. They do BDD because someone told them they should. No one ever reads the scenarios when they are completed. It is just an extra layer of complexity in your test framework.&lt;/p&gt;

&lt;p&gt;Worse still the scenarios which are meant to be readable by anyone are poorly written. I have seen versions of the below &lt;em&gt;many&lt;/em&gt; times:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Given I visit www.google.com
And I check that the 'Search' button is on the page
And I check that the 'Feeling Lucky' button is on the page
And I check the Google Logo is on the page
And I enter the search term 'BDD is fun'
And I click the 'Search Button'
Then I see the Search results page
And The page has results
And they are clickable
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;That is a mild example (because I got bored) - I have seen many that are much worse.&lt;/p&gt;

&lt;h4 id=&quot;read-more-2&quot;&gt;Read More&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.codewithjason.com/recommend-against-cucumber/&quot;&gt;Why I recommend against using Cucumber&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;be-honest-and-critical&quot;&gt;Be Honest and Critical&lt;/h2&gt;
&lt;p&gt;You are in an interview to show someone two main things - that you are &lt;a href=&quot;https://www.joelonsoftware.com/2006/10/25/the-guerrilla-guide-to-interviewing-version-30/&quot;&gt;Smart and Get Things Done&lt;/a&gt;. (I know there are other skills to display as well…)&lt;/p&gt;

&lt;p&gt;Being &lt;em&gt;Honest and Critical&lt;/em&gt; about testing trends and tools shows me you are smart. It potentially shows me that you want to get things done too by avoiding doing things for the sake of doing them.&lt;/p&gt;</content><author><name>Thomas Shipley</name></author><category term="interviewing" /><category term="interviews" /><summary type="html">The Lego Movie Got It Wrong and That is OK</summary></entry><entry><title type="html">Visualising API Performance Results With GCP BigQuery and Google Sheets</title><link href="/performance/2020/01/15/visualising-api-performance-results-with-gcp-bigquery-and-google-sheets.html" rel="alternate" type="text/html" title="Visualising API Performance Results With GCP BigQuery and Google Sheets" /><published>2020-01-15T14:17:49+00:00</published><updated>2020-01-15T14:17:49+00:00</updated><id>/performance/2020/01/15/visualising-api-performance-results-with-gcp-bigquery-and-google-sheets</id><content type="html" xml:base="/performance/2020/01/15/visualising-api-performance-results-with-gcp-bigquery-and-google-sheets.html">&lt;h2 id=&quot;api-performance-problems-lets-capture-more-data&quot;&gt;API Performance Problems: Lets Capture More Data&lt;/h2&gt;
&lt;p&gt;The performance tests were failing seemingly randomly. No one on my team knew why our API would suddenly fail on the 99th or 95th percentiles. They wanted easy access to data and visualisations.&lt;/p&gt;

&lt;p&gt;We use Gatling for our performance tests and our service runs in Google Cloud Platform (GCP). What if performance statistics from Gatling could be captured and stored in GCP to be visualised using a self-service approach. Turns out they can.&lt;/p&gt;
&lt;h2 id=&quot;solution-overview&quot;&gt;Solution Overview&lt;/h2&gt;
&lt;p&gt;Gatling stores test statistics in JSON files on disk (more below) those stats can be parsed, stored in GCP Datastore and then using a Datastore backup (in GCP Storage) the results can be loaded into GCP Big Query. From there you can use Google Sheets to load the data into a spreadsheet. Once in Google Sheets, you can do all the usual things you might do with a spreadsheet. Create some pretty graphs, a pie chart maybe.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Datastore --&amp;gt; Storage (Bucket) --&amp;gt; BigQuery --&amp;gt; Google Sheets&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;That sounds like a lot of moving parts and it is.&lt;/em&gt; But the moving parts individually are simple and work together well. The individual tasks are &lt;em&gt;not hard to setup&lt;/em&gt;. Let’s start with Gatling.&lt;/p&gt;
&lt;h2 id=&quot;gathering-data-from-gatling&quot;&gt;Gathering Data from Gatling&lt;/h2&gt;
&lt;p&gt;The first stage is to get the performance stats from Gatling. Starting in the report folder generated by your Gatling test there are two key files that I used for stats:&lt;/p&gt;

&lt;h3 id=&quot;jsassertionsjson&quot;&gt;./js/assertions.json&lt;/h3&gt;
&lt;p&gt;This file contains the details of all the assertions you make within your test. This is handy as, chances are all the performance stats you care about are in here as your test asserts on them.&lt;/p&gt;

&lt;h4 id=&quot;json-structure&quot;&gt;JSON Structure&lt;/h4&gt;
&lt;p&gt;The file contains one JSON object with the following structure:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
    &quot;simulation&quot;: &quot;simulation-name&quot;,
    &quot;simulationId&quot;: &quot;simulation-id&quot;,
    &quot;start&quot;: 1576246324329,
    &quot;description&quot;: &quot;&quot;,
    &quot;scenarios&quot;: [
        &quot;scenario1&quot;,
        &quot;scenario2&quot;
    ],
    &quot;assertions&quot;: [
        {
            &quot;path&quot;: &quot;path_to_assertion_target&quot;,
            &quot;target&quot;: &quot;percentage of successful events&quot;,
            &quot;condition&quot;: &quot;is greater than&quot;,
            &quot;expectedValues&quot;: [
                99.9
            ],
            &quot;result&quot;: false,
            &quot;message&quot;: &quot;path_to_assertion_target: percentage of successful events is greater than 99.9&quot;,
            &quot;actualValue&quot;: [
                0.0
            ]
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;jsglobal_statsjson&quot;&gt;./js/global_stats.json&lt;/h3&gt;
&lt;p&gt;If you don’t assert on the values you want to capture (it is perhaps worth double-checking why you care about them if you don’t assert on them) then your second source of data is global_stats.json. It contains the key stats you might need such as percentiles and response times.&lt;/p&gt;

&lt;p&gt;However, one thing to note is the percentile fields follow a Gatling naming convention instead of a clearer 99th, 95th and so on. Use this mapping to help:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Percentile&lt;/th&gt;
      &lt;th&gt;Gatling Percentile Name&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;50th&lt;/td&gt;
      &lt;td&gt;Percentiles 1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;75th&lt;/td&gt;
      &lt;td&gt;Percentiles 2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;95th&lt;/td&gt;
      &lt;td&gt;Percentiles 3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;99th&lt;/td&gt;
      &lt;td&gt;Percentiles 4&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Also note the information on groups are setup either using the defaults or by what is in your Gatling config but the naming is consistent regardless (e.g. group1, group2, group3 and group4).&lt;/p&gt;

&lt;h4 id=&quot;json-structure-1&quot;&gt;JSON Structure&lt;/h4&gt;
&lt;p&gt;The file contains one JSON object with multiple sub-objects within it:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
    &quot;name&quot;: &quot;Global Information&quot;,
    &quot;numberOfRequests&quot;: {
        &quot;total&quot;: 1460,
        &quot;ok&quot;: 0,
        &quot;ko&quot;: 1840
    },
    &quot;minResponseTime&quot;: {
        &quot;total&quot;: 41,
        &quot;ok&quot;: 0,
        &quot;ko&quot;: 41
    },
    &quot;maxResponseTime&quot;: {
        &quot;total&quot;: 3550,
        &quot;ok&quot;: 0,
        &quot;ko&quot;: 3550
    },
    &quot;meanResponseTime&quot;: {
        &quot;total&quot;: 146,
        &quot;ok&quot;: 0,
        &quot;ko&quot;: 146
    },
    &quot;standardDeviation&quot;: {
        &quot;total&quot;: 365,
        &quot;ok&quot;: 0,
        &quot;ko&quot;: 365
    },
    &quot;percentiles1&quot;: {
        &quot;total&quot;: 63,
        &quot;ok&quot;: 0,
        &quot;ko&quot;: 63
    },
    &quot;percentiles2&quot;: {
        &quot;total&quot;: 72,
        &quot;ok&quot;: 0,
        &quot;ko&quot;: 72
    },
    &quot;percentiles3&quot;: {
        &quot;total&quot;: 761,
        &quot;ok&quot;: 0,
        &quot;ko&quot;: 761
    },
    &quot;percentiles4&quot;: {
        &quot;total&quot;: 9999,
        &quot;ok&quot;: 0,
        &quot;ko&quot;: 9999
    },
    &quot;group1&quot;: {
    &quot;name&quot;: &quot;t &amp;lt; 55 ms&quot;,
    &quot;count&quot;: 0,
    &quot;percentage&quot;: 0
},
    &quot;group2&quot;: {
    &quot;name&quot;: &quot;55 ms &amp;lt; t &amp;lt; 75 ms&quot;,
    &quot;count&quot;: 0,
    &quot;percentage&quot;: 0
},
    &quot;group3&quot;: {
    &quot;name&quot;: &quot;t &amp;gt; 75 ms&quot;,
    &quot;count&quot;: 0,
    &quot;percentage&quot;: 0
},
    &quot;group4&quot;: {
    &quot;name&quot;: &quot;failed&quot;,
    &quot;count&quot;: 18191,
    &quot;percentage&quot;: 100
},
    &quot;meanNumberOfRequestsPerSecond&quot;: {
        &quot;total&quot;: 12,
        &quot;ok&quot;: 0,
        &quot;ko&quot;: 9
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;pushing-gatling-data-into-gcp-datastore&quot;&gt;Pushing Gatling Data into GCP Datastore&lt;/h2&gt;
&lt;p&gt;With the data found, we can move it into GCP Datastore. Briefly, GCP Datastore is a NoSQL database offered by GCP. It is perfect for storing data like this where we don’t care about modding data relationships and just storing the data.&lt;/p&gt;

&lt;p&gt;Personally I used Python to parse the Gatling JSON files and push the data into Datastore. At the time of writing the python packages I used for GCP were:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;google-api-core==1.14.3
google-auth==1.8.2
google-cloud-core==1.1.0
google-cloud-datastore==1.10.0
googleapis-common-protos==1.6.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;These things update all the time so check the latest so check &lt;a href=&quot;https://pypi.org/project/google-cloud-datastore/&quot;&gt;pypi package listings&lt;/a&gt; for the latest versions to use.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If you are new to Python take a look at &lt;a href=&quot;https://docs.python-guide.org/dev/virtualenvs/&quot;&gt;Pip and VirtualEnv&lt;/a&gt; which makes managing your python packages easy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is a bit beyond the scope of this post to teach GCP &amp;amp; Datastore but assuming you have some knowledge of both these topics then this example should get you started:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Dict containing my stats...
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;perf_stat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;stat_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;MyStatKey&quot;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Code to populate dict from JSON files... omitted
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Create, populate and persist an entity
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datastore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;mynamespace&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;project&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;myproject&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;stat_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'MyDataKind'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;entity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datastore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Entity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stat_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;entity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'testRunId'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;perf_stat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'testRunId'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'lastUpdated'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dt2ts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datetime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()),&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'testRunStartTimestampUtc'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;perf_stat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'testRunStartTimestampUtc'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'global_min_response_time_ms'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;perf_stat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'global_min_response_time'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'global_max_response_time_ms'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;perf_stat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'global_max_response_time'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'global_mean_response_time_ms'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;perf_stat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'global_mean_response_time'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'global_mean_requests_per_second'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;perf_stat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'global_mean_requests_per_second'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;backing-up-the-data-to-gcp-storage&quot;&gt;Backing Up the Data to GCP Storage&lt;/h2&gt;
&lt;p&gt;With the stats captured in Datastore, you could stop here and tell the rest of your team to access the data via &lt;a href=&quot;https://console.cloud.google.com&quot;&gt;GCP Cloud Console&lt;/a&gt;. That would work but (particularly with lots of stats captured) the data can be hard to read.&lt;/p&gt;

&lt;p&gt;Instead, we are going to load a backup of the data into a bucket using Storage. Using this backup we can load the data into BigQuery and view it using Google Sheets.&lt;/p&gt;

&lt;h3 id=&quot;create-a-gcp-storage-bucket&quot;&gt;Create a GCP Storage Bucket&lt;/h3&gt;
&lt;p&gt;First, create a Bucket in Storage to store the backup. I also set the retention policy on our Bucket to 7 days because in our implementation this data was loaded into BigQuery as soon as the backup was completed. Once the data is in BigQuery the backup is no longer needed.&lt;/p&gt;

&lt;h3 id=&quot;create-a-datastore-backup-into-your-bucket&quot;&gt;Create a Datastore Backup into your Bucket&lt;/h3&gt;
&lt;p&gt;With the bucket created there are a number of ways to create a datastore backup to it. But I used the command line during our deployment pipeline.&lt;/p&gt;

&lt;p&gt;Create a bash file and first make sure you are authenticated using the pipeline:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gcloud auth activate-service-account &lt;span class=&quot;nt&quot;&gt;--key-file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;my_key.json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now add to your bash file the command to start the backup:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Backup the perf data to a bucket and wait&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;urlPrefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;gcloud datastore &lt;span class=&quot;nb&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--kinds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'MyDataKind'&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--namespaces&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'MyNamespace'&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;json gs://my-bucket-gs-url | jq &lt;span class=&quot;nt&quot;&gt;--raw-output&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'.metadata.outputUrlPrefix'&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The key part of that snippet is the usage of &lt;a href=&quot;https://stedolan.github.io/jq/&quot;&gt;jq&lt;/a&gt; (which you may need to install). It grabs the first part of the URL returned by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcloud&lt;/code&gt; command which tells you where your backup is stored. You will need that for the next part.&lt;/p&gt;

&lt;h2 id=&quot;loading-the-data-into-gcp-bigquery&quot;&gt;Loading the Data into GCP BigQuery&lt;/h2&gt;
&lt;p&gt;With the backup now in your bucket here is the final part. Loading the data into BigQuery. BigQuery is a serverless data warehouse solution provided by GCP. It looks very powerful and complicated but for our purpose it is actually quite simple.&lt;/p&gt;

&lt;p&gt;First using the GCP Cloud Console navigate to BigQuery and create a &lt;a href=&quot;https://cloud.google.com/bigquery/docs/datasets&quot;&gt;dataset&lt;/a&gt; and &lt;a href=&quot;https://cloud.google.com/bigquery/docs/tables&quot;&gt;table&lt;/a&gt; within it to store your data in.&lt;/p&gt;

&lt;p&gt;Update your bash script (the same one with the backup logic) to load the data into BiqQuery:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Import datastore backup into big data&lt;/span&gt;
bq &lt;span class=&quot;nt&quot;&gt;--location&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;europe-west2 load &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;--source_format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;DATASTORE_BACKUP &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;--replace&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
mynamespace:bigquery_dataset_name.bigquery_table_name &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$urlPrefix&lt;/span&gt;/namespace_mynamespace/kind_MyDataKind/namespace_mynamespace_kind_MyDatakind.export_metadata
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The key things to note in the snippet above:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;It uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$urlPrefix&lt;/code&gt; defined earlier in your bash script to know where to look for the backup.&lt;/li&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bq&lt;/code&gt; command used to load the backup into BigQuery has the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--replace&lt;/code&gt; flag passed to it. This is important for us as it we never want to append data to BigQuery - just use the latest backup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With that done your data is in BigQuery and ready to use by Google Sheets.&lt;/p&gt;

&lt;h2 id=&quot;bonus-accessing-the-gcp-bigquery-data-from-google-sheets&quot;&gt;Bonus! Accessing the GCP BigQuery Data from Google Sheets&lt;/h2&gt;
&lt;p&gt;Google Sheets can access data stored in BigQuery. It does so using a &lt;a href=&quot;https://cloud.google.com/blog/products/g-suite/connecting-bigquery-and-google-sheets-to-help-with-hefty-data-analysis&quot;&gt;Data Connector&lt;/a&gt; found under the &lt;em&gt;Data&lt;/em&gt; menu.&lt;/p&gt;

&lt;p&gt;This is a simple wizard to follow. Tell it the dataset and table you want and the query you want to use to get your data and that is it. The data is inserted in a Sheet and you are ready to go.&lt;/p&gt;

&lt;p&gt;When you want to get the latest version of the data just hit the &lt;em&gt;Refresh&lt;/em&gt; button on the bottom left.&lt;/p&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;By following this post you have (or are perhaps planning to) string together a couple of GCP services in a relatively simple way:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Datastore --&amp;gt; Storage (Bucket) --&amp;gt; BigQuery --&amp;gt; Google Sheets&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The reward for this plumbing work is a more friendly way to allow your whole team to access performance data. Everyone on your team is probably familiar with spreadsheets. The less technical members of your team don’t need to understand the other services sitting underneath delivering this information to the sheet. Finally, it can all be orchestrated via your deployment pipeline.&lt;/p&gt;

&lt;p&gt;It is still early days for my team but so far letting them manipulate performance data themselves has proven quite useful. It is self-service and they can create any number of visualisations they like using a familiar tool.&lt;/p&gt;</content><author><name>Thomas Shipley</name></author><category term="performance" /><category term="gcp" /><category term="performance" /><category term="gatling" /><summary type="html">API Performance Problems: Lets Capture More Data The performance tests were failing seemingly randomly. No one on my team knew why our API would suddenly fail on the 99th or 95th percentiles. They wanted easy access to data and visualisations.</summary></entry><entry><title type="html">Introduction to Automated Security Testing with OWASP Zap, Dependency Checker and Glue.</title><link href="/uncategorised/2019/04/09/introduction-to-automated-api-security-testing-with-owasp-zap-dependency-checker-and-glue.html" rel="alternate" type="text/html" title="Introduction to Automated Security Testing with OWASP Zap, Dependency Checker and Glue." /><published>2019-04-09T17:44:49+01:00</published><updated>2019-04-09T17:44:49+01:00</updated><id>/uncategorised/2019/04/09/introduction-to-automated-api-security-testing-with-owasp-zap-dependency-checker-and-glue</id><content type="html" xml:base="/uncategorised/2019/04/09/introduction-to-automated-api-security-testing-with-owasp-zap-dependency-checker-and-glue.html">&lt;p&gt;Security testing can be really time-consuming. Ever tried to organise a penetration test for your website? It is expensive! For my current client, we wanted to think about how much security testing can be done ahead of time in an automated way. Not as a replacement for professional penetration testing but as a way to give us some confidence before that stage that we are catching issues as early as we can.&lt;/p&gt;

&lt;p&gt;I did this by adding automated security tests for common issues in our codebase. For example, insecure dependencies or API endpoints that are vulnerable to SQL injection attempts. The Open Web Application Security Project (&lt;a rel=&quot;noreferrer noopener&quot; aria-label=&quot; (opens in a new tab)&quot; href=&quot;https://www.owasp.org/index.php/Main_Page&quot; target=&quot;_blank&quot;&gt;OWASP&lt;/a&gt;) has a couple of tools that can help with this. &lt;strong&gt;OWASP Dependency Checker, ZAP and Glue&lt;/strong&gt;. In this post, I will introduce them all and how they are meant to work together.&lt;/p&gt;

&lt;h2 id=&quot;dependency-checker---verifying-code-you-consume&quot;&gt;Dependency Checker - Verifying Code you Consume&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.owasp.org/index.php/OWASP_Dependency_Check&quot; target=&quot;_blank&quot; rel=&quot;noreferrer noopener&quot; aria-label=&quot; (opens in a new tab)&quot;&gt;Dependency checker&lt;/a&gt; does what the name suggests - it checks your dependencies looking for ones with known vulnerabilities. Once it finds some it will let you know what they are a link to the National Vulnerability Database (&lt;a rel=&quot;noreferrer noopener&quot; aria-label=&quot; (opens in a new tab)&quot; href=&quot;https://nvd.nist.gov/&quot; target=&quot;_blank&quot;&gt;NVD&lt;/a&gt;). It is fast, easy to set up and gives you some confidence that your code is built on a solid foundation.&lt;/p&gt;

&lt;p&gt;Checking your dependencies is one of the first things you should do when looking to add automated verification of your application’s security - it is a quick win! Check the paper &lt;a href=&quot;https://cdn2.hubspot.net/hub/203759/file-1100864196-pdf/docs/Contrast_-_Insecure_Libraries_2014.pdf&quot; target=&quot;_blank&quot; rel=&quot;noreferrer noopener&quot; aria-label=&quot; (opens in a new tab)&quot;&gt;Unfortunate Reality of Insecure Libraries&lt;/a&gt; to understand more about the scale of the problem.&lt;/p&gt;

&lt;h2 id=&quot;zap---verifying-code-you-write&quot;&gt;ZAP - Verifying Code you Write&lt;/h2&gt;

&lt;p&gt;With your dependencies checked what about your own code. Zed Attack Proxy (&lt;a rel=&quot;noreferrer noopener&quot; aria-label=&quot; (opens in a new tab)&quot; href=&quot;https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project&quot; target=&quot;_blank&quot;&gt;ZAP&lt;/a&gt;) is the tool for this. It checks your code by doing both passive and active attacks against your site or API. Passive attacks are things like information disclosure such as your server version in the headers. In contrast, active attacks directly attack your application using attack vectors such as SQL injection.&lt;/p&gt;

&lt;p&gt;One thing to keep in mind is the Active attacks can cause your site issues - after all, they are malicious requests! So it is best to run this tool against a test environment rather than the live site.&lt;/p&gt;

&lt;h2 id=&quot;glue---bringing-results-together&quot;&gt;Glue - Bringing Results Together&lt;/h2&gt;

&lt;p&gt;The two tools above will produce plenty of results to look at. But like all security testing tools, they produce false positives. Without a clear way to manage this, it can become painful quickly. &lt;a rel=&quot;noreferrer noopener&quot; aria-label=&quot; (opens in a new tab)&quot; href=&quot;https://www.owasp.org/index.php/OWASP_Glue_Tool_Project&quot; target=&quot;_blank&quot;&gt;Glue&lt;/a&gt; helps with this by processing the output of Dependency Checker and Zap and publishing the results somewhere for you to review and if need be mark issues as false positives.&lt;/p&gt;

&lt;p&gt;For example, in my setup, I set up glue to interact with the JIRA project for my team. Now once the security tests are completed the issues found are automatically raised in JIRA where engineers can review them. By doing this we make sure test results are addressed and any false positives can be marked as such.&lt;/p&gt;

&lt;p&gt;Glue will even run a lot of tools for you. Although I had more success with &lt;a href=&quot;https://github.com/OWASP/glue/blob/master/docs/dynamic_task.md&quot;&gt;Dynamic Tasks&lt;/a&gt; and would recommend them instead of using the built-in ones.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;Using the three tools together as part of your CI pipeline gives you the ability to address security issues sooner than you might usually. Although it is important to remember that all security tools report false positives and do not catch everything so in my opinion these tools are best used to complement a professional security review for your project. But if you haven’t the budget for one of them then these tools might help you get some confidence!&lt;/p&gt;</content><author><name>Thomas Shipley</name></author><category term="Uncategorised" /><category term="owasp" /><category term="security" /><summary type="html">Security testing can be really time-consuming. Ever tried to organise a penetration test for your website? It is expensive! For my current client, we wanted to think about how much security testing can be done ahead of time in an automated way. Not as a replacement for professional penetration testing but as a way to give us some confidence before that stage that we are catching issues as early as we can.</summary></entry><entry><title type="html">Quickstart: Try Static Analysis with SonarQube and Docker</title><link href="/sonarqube/uncategorised/2018/11/06/quickstart-try-static-analysis-with-sonarqube-and-docker.html" rel="alternate" type="text/html" title="Quickstart: Try Static Analysis with SonarQube and Docker" /><published>2018-11-06T14:51:34+00:00</published><updated>2018-11-06T14:51:34+00:00</updated><id>/sonarqube/uncategorised/2018/11/06/quickstart-try-static-analysis-with-sonarqube-and-docker</id><content type="html" xml:base="/sonarqube/uncategorised/2018/11/06/quickstart-try-static-analysis-with-sonarqube-and-docker.html">&lt;p&gt;Recently I started a new contract and was in the rare position of joining a team before the developers! Without a team producing work, I wanted to think about ways to get the team off to a good start. My last post was about static analysis with Sonarqube. I love static analysis tools they are like an additional tester in your team and when the results are taken in the context of the wider effort they can be really valuable. Below I want to show you how to set up a quick proof of concept Sonarqube server to discuss with your team.&lt;/p&gt;

&lt;h1 id=&quot;overview&quot;&gt;Overview&lt;/h1&gt;

&lt;p&gt;Before starting this guide I assume you have a superficial level of Docker knowledge (I am not an expert) and you have it installed. &lt;strong&gt;There are three steps to getting started in total it will probably take 15 minutes&lt;/strong&gt; (excluding download times):&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Create a docker image with SonarQube installed using &lt;a href=&quot;https://hub.docker.com/_/sonarqube/&quot;&gt;Docker Hub&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Run the docker image just created.&lt;/li&gt;
  &lt;li&gt;Install Sonar-Scanner and create a SonarQube properties file in the root of your project to run a scan.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;create-a-sonarqube-docker-container&quot;&gt;Create a SonarQube Docker Container&lt;/h1&gt;

&lt;p&gt;To use SonarQube you need to be running the server somewhere. We will use &lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt;. It will download a docker image which contains SonarQube for us already configured and set it up as a container on your machine. To do this open your command window and type:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; sonarqube &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 9000:9000 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 9092:9092 sonarqube
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The output of this command should look similar to:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Unable to find image &lt;span class=&quot;s1&quot;&gt;'sonarqube:latest'&lt;/span&gt; locally
latest: Pulling from library/sonarqube
bc9ab73e5b14: Pull &lt;span class=&quot;nb&quot;&gt;complete 
&lt;/span&gt;193a6306c92a: Pull &lt;span class=&quot;nb&quot;&gt;complete 
&lt;/span&gt;e5c3f8c317dc: Pull &lt;span class=&quot;nb&quot;&gt;complete 
&lt;/span&gt;a587a86c9dcb: Pull &lt;span class=&quot;nb&quot;&gt;complete 
&lt;/span&gt;a4c7ee7ef122: Pull &lt;span class=&quot;nb&quot;&gt;complete 
&lt;/span&gt;a7c0dad691e9: Pull &lt;span class=&quot;nb&quot;&gt;complete 
&lt;/span&gt;367a6a68b113: Pull &lt;span class=&quot;nb&quot;&gt;complete 
&lt;/span&gt;60c0e52d1ec2: Pull &lt;span class=&quot;nb&quot;&gt;complete 
&lt;/span&gt;c9d22bc43935: Pull &lt;span class=&quot;nb&quot;&gt;complete 
&lt;/span&gt;884af0bfbb9a: Pull &lt;span class=&quot;nb&quot;&gt;complete 
&lt;/span&gt;35a8cd0c916a: Pull &lt;span class=&quot;nb&quot;&gt;complete 
&lt;/span&gt;9f9ecbe7a343: Pull &lt;span class=&quot;nb&quot;&gt;complete 
&lt;/span&gt;af800bded4f3: Pull &lt;span class=&quot;nb&quot;&gt;complete 
&lt;/span&gt;Digest: sha256:cc57b262ee9e7145456dee8c7ae24622c82b22cabeaac4651e7dd642da806f2e
Status: Downloaded newer image &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;sonarqube:latest
a263b203864adc366919ba9cde3cde87542c96046af7a8b9d7ebc1f155ec2204
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will download the latest SonarQube image from Docker Hub and will set up a container using it. To start your server you just need to run this container.&lt;/p&gt;

&lt;h1 id=&quot;run-the-sonarqube-docker-container&quot;&gt;Run the SonarQube Docker Container&lt;/h1&gt;

&lt;p&gt;Now if you run: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker container ls&lt;/code&gt; in your command window you should see your container named &lt;em&gt;sonarqube -&lt;/em&gt; for example:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;My-MacBook-Pro:kotlin thomas$ docker container ls
CONTAINER ID   IMAGE       COMMAND         CREATED           STATUS            PORTS                                            NAMES
68be74d0aa51   sonarqube   &quot;./bin/run.sh&quot;  About an hour ago Up About an hour  0.0.0.0:9000-&amp;gt;9000/tcp, 0.0.0.0:9092-&amp;gt;9092/tcp   gracious_noyce
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now you are ready to start the SonarQube server using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker run sonarqube&lt;/code&gt; command. If this was successful you should see your command window fill with text about the server starting and once loaded be able to see the dashboard at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://localhost:9000&lt;/code&gt;. Now you can scan your project.&lt;/p&gt;

&lt;h1 id=&quot;scan-your-project-with-sonar-scanner&quot;&gt;Scan your Project with Sonar-Scanner&lt;/h1&gt;

&lt;p&gt;To have some results in your proof of concept SonarQube server you need to scan a project. &lt;a href=&quot;https://www.sonarqube.org/features/multi-languages/&quot;&gt;Sonarqube supports a host of languages&lt;/a&gt; so pick a project written in a supported language (you may need to install a plugin). Next, make sure you have the &lt;a href=&quot;https://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner&quot;&gt;Sonar-Scanner&lt;/a&gt; application which you can run from your command window. But before you run it at the root of your project add a &lt;em&gt;sonar-project.properties&lt;/em&gt; file. This will tell the scanner a bit about your project and where to send the results. Below is an example of the minimum required information:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#----- SonarQube server
sonar.host.url=http://localhost:9000

#----- Project Key
sonar.projectKey=4a27fa8c666747f6956d75ae63fb24b9

#----- Project Name
sonar.projectName=MyProjectName

#----- Project Version
sonar.projectVersion=1.0

#----- Source files (relative)
sonar.sources=.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The projectKey needs to be unique to your project on the SonarQube server and the rest is self-explanatory. With all this in place with your command line in the root of the project where the sonar-scanner is located (unless you have installed it in another way such as with &lt;a href=&quot;https://brew.sh/&quot;&gt;Homebrew&lt;/a&gt;) enter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sonar-scanner&lt;/code&gt; and press enter. You will see an output like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;My-MacBook-Pro:kotlin thomas$ sonar-scanner
&amp;lt;Redacted for brevity&amp;gt;
INFO: ANALYSIS SUCCESSFUL, you can browse http://localhost:9000/dashboard/index/4a27fa8c666747f6956d75ae63fb24b9
INFO: Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report
INFO: More about the report processing at http://localhost:9000/api/ce/task?id=AWbpY5h5xoaTc7Huvu3D
INFO: Task total time: 4.403 s
INFO: ------------------------------------------------------------------------
INFO: EXECUTION SUCCESS
INFO: ------------------------------------------------------------------------
INFO: Total time: 5.628s
INFO: Final Memory: 11M/50M
INFO: ------------------------------------------------------------------------
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once completed your results will be in the SonarQube dashboard by following the link. Now start to play around with SonarQube and your team’s projects!&lt;/p&gt;</content><author><name>Thomas Shipley</name></author><category term="SonarQube" /><category term="Uncategorised" /><summary type="html">Recently I started a new contract and was in the rare position of joining a team before the developers! Without a team producing work, I wanted to think about ways to get the team off to a good start. My last post was about static analysis with Sonarqube. I love static analysis tools they are like an additional tester in your team and when the results are taken in the context of the wider effort they can be really valuable. Below I want to show you how to set up a quick proof of concept Sonarqube server to discuss with your team.</summary></entry><entry><title type="html">Static Analysis for .NET Core Projects using SonarQube</title><link href="/.net%20core/ci/qa/sonarqube/2018/03/21/static-analysis-for-net-core-projects-using-sonarqube.html" rel="alternate" type="text/html" title="Static Analysis for .NET Core Projects using SonarQube" /><published>2018-03-21T13:54:00+00:00</published><updated>2018-03-21T13:54:00+00:00</updated><id>/.net%20core/ci/qa/sonarqube/2018/03/21/static-analysis-for-net-core-projects-using-sonarqube</id><content type="html" xml:base="/.net%20core/ci/qa/sonarqube/2018/03/21/static-analysis-for-net-core-projects-using-sonarqube.html">&lt;p&gt;Static analysis is a way of automatically analysing code without executing it. As a development team, this is really powerful as once the static analysis software is up, running and integrated with your deployment pipelines you can gain an extra tester in your team with little ongoing maintenance! While some of the issues static analysis software finds are not always high value (code styling for example) some are issues your engineers are less likely to notice such as obscure security flaws and out of date dependencies.&lt;/p&gt;

&lt;h2 id=&quot;sonarqube-a-static-analysistool&quot;&gt;SonarQube; A Static Analysis Tool&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.sonarqube.org/&quot;&gt;SonarQube&lt;/a&gt; is a static analysis tool that I have been using and evangelising at Just Eat. Some of the issues it finds:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Logic Bugs
    &lt;ul&gt;
      &lt;li&gt;&lt;em&gt;Example&lt;/em&gt;: Checking for null on an object that is always null.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Security Vulnerabilities
    &lt;ul&gt;
      &lt;li&gt;&lt;em&gt;Example&lt;/em&gt;: Passwords in the source code&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Code Smells
    &lt;ul&gt;
      &lt;li&gt;&lt;em&gt;Example&lt;/em&gt;: Hardcoded URIs and Methods with a high &lt;a href=&quot;https://en.wikipedia.org/wiki/Cyclomatic_complexity&quot;&gt;Cyclomatic Complexity&lt;/a&gt; score.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Test Coverage
    &lt;ul&gt;
      &lt;li&gt;SonarQube, however, does not calculate this by itself but instead &lt;a href=&quot;https://docs.sonarqube.org/display/SONAR/Seeing+Coverage&quot;&gt;ingests test reports from your CI build&lt;/a&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Code Duplication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This information is all collated and displayed in a central dashboard for your project which gives you an overall view of the “quality” of your project. While some of the issues above might seem trivial (the code smells category is often guilty of this) even in these cases, monitoring the trivial metrics to see if they deteriorate over time is a useful measure for standards dropping within your team.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/2018/03/SonarQube_Project_page.png&quot; alt=&quot;Example SonarQube Project Dashboard&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;quality-gates&quot;&gt;Quality Gates&lt;/h3&gt;

&lt;p&gt;Related to dropping standards are what SonarQube calls Quality Gates. Using these you can set triggers to throw either warnings or errors in your CI builds based on rules set in your Quality Gate. Example rules include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Code Coverage below X%&lt;/li&gt;
  &lt;li&gt;Bug Count increased by X from the last build&lt;/li&gt;
  &lt;li&gt;Vulnerability Count increased by X from the last build&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any of these rules are broken you can choose to throw warnings or errors during your build process. Sonarqube can even be set up to break your build. But in my opinion, this isn’t a good idea.&lt;/p&gt;

&lt;h3 id=&quot;the-case-against-breaking-the-build&quot;&gt;The Case Against Breaking the Build&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/SonarQubeCommunity/sonar-build-breaker&quot;&gt;BuildBreaker&lt;/a&gt; is an official SonarQube plugin which you can use to break your CI builds if a Quality Gate triggers any errors. On the face of it, this makes sense. You as a QA want your developers to maintain high standards so stopping them from breaking the Quality Gate rules by stopping there build from succeeding is an easy way to do this.&lt;/p&gt;

&lt;p&gt;But if only it were that simple. Setting up SonarQube in this way has some key disadvantages:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It encourages the often observed us vs them dynamic between developer and QA.&lt;/li&gt;
  &lt;li&gt;In continuous delivery environments, you are now holding up a build. In the best case, the Quality Gate has detected a serious drop in quality or worse case trivial issue(s) have caused the build to fail. This won’t make QA popular.&lt;/li&gt;
  &lt;li&gt;Breaking the build is likely to discourage developer buy-in. Without buy-in from your team, the issues found by SonarQube will never be resolved.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SonarQube should be used as a passive monitor of the health of your projects. By using it in this way you can start to work with your team rather than against them and use the metrics SonarQube discovers to start having conversations about how things might improve and even get involved in improving them yourself! SonarQube themselves did a blog post &lt;a href=&quot;https://blog.sonarsource.com/why-you-shouldnt-use-build-breaker/&quot;&gt;“Why You Shouldn’t Use Build Breaker”&lt;/a&gt; with similar opinions.&lt;/p&gt;

&lt;h3 id=&quot;github-integration&quot;&gt;Github Integration&lt;/h3&gt;

&lt;p&gt;The final feature of SonarQube you should be aware of is it’s GitHub integration. With the &lt;a href=&quot;https://github.com/SonarSource/sonar-github&quot;&gt;Sonar-Github&lt;/a&gt; plugin, you can set up integration with Github to comment on Pull Requests (PR) with issues found by SonarQube in the changes during your CI builds.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/2018/03/sonarqube_PullRequestAnalysis.png&quot; alt=&quot;SonarQube and GitHub integration example.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;One issue to note is you will probably want to differentiate between PR builds and builds of your &lt;em&gt;master&lt;/em&gt; branch.&lt;/p&gt;

&lt;p&gt;SonarQube keeps a track of your latest build results to compare the next build to for purpose of its Quality Gate. However, for PR builds you probably don’t want the results stored as you want to always compare the PR build to latest results from _master _otherwise a developer could just rebuild their branch in CI and the new issues previously found would no longer be new and disappear! Below is a PowerShell script I have used in teams to do this differentiation between PR and master branches:&lt;/p&gt;

&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$github_branch_refs_parts&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;%teamcity.build.branch%&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-split&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$is_pr&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$github_branch_refs_parts&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Count&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-eq&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-and&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$github_branch_refs_parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-eq&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;merge&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-Not&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$is_pr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write-Host&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Running SonarQube in master branch mode&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;    
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SonarQube.Scanner.MSBuild.exe&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;/k:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;%sonar.project%&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;/d:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;sonar.host.url=%sonar.host.url%&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;/d:sonar.cs.dotcover.reportsPaths&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;dotCover.html&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;/v:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;%build.number%&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write-Host&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Running SonarQube in PR Mode&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$pull_request_number&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$github_branch_refs_parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$repo&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;%repo_owner%&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;%name%&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$command&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'SonarQube.Scanner.MSBuild.exe'&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' begin'&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; 
    &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' /k:'&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'%sonar_project%'&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; 
    &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' /v:'&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;%build_number%&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' /d:sonar.host.url='&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;%sonar_hosturl%&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' /d:sonar.github.pullRequest='&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$pull_request_number&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' /d:sonar.github.repository='&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$repo&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' /d:sonar.github.oauth='&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;%sonarqube_github_oauth_token%&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' /d:sonar.analysis.mode='&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;preview&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' /d:sonar.scanAllFiles='&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' /d:sonar.github.endpoint='&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;%github_api_endpoint%&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write-Host&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$command&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; 
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Invoke-Expression&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$command&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The key difference between the two &lt;em&gt;SonarQube.Scanner.MSBuild.exe&lt;/em&gt; commands is in the analysis mode &lt;a href=&quot;https://blog.sonarsource.com/analysis-vs-preview-vs-incremental-preview-in-sonarqube/&quot;&gt;&lt;em&gt;Preview&lt;/em&gt;&lt;/a&gt; the results are not saved by the SonarQube server so the comparison is always done against the latest &lt;em&gt;master&lt;/em&gt; build instead.&lt;/p&gt;

&lt;h4 id=&quot;analysis-mode-preview-deprecated-in-sonarqube-66&quot;&gt;Analysis Mode Preview Deprecated in SonarQube 6.6&lt;/h4&gt;

&lt;p&gt;The Preview option is being deprecated according to the &lt;a href=&quot;https://docs.sonarqube.org/display/SONAR/Analysis+Parameters&quot;&gt;documentation&lt;/a&gt;, however, I have not seen an alternative proposed yet so cannot suggest how you might handle this in SonarQube 6.6+.&lt;/p&gt;

&lt;h2 id=&quot;setup-sonarqube-with-a-net-core-project&quot;&gt;Setup SonarQube with a .NET Core Project&lt;/h2&gt;

&lt;p&gt;SonarQube now &lt;a href=&quot;https://www.sonarsource.com/resources/product-news/news.html#2017-04-13-sonarqube-scanner-for-msbuild-2-3-released&quot;&gt;supports .NET Core&lt;/a&gt; as of SonarQube Scanner for MSBuild version 2.3. So the setup is actually quite simple:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Install the SonarQube Scanner on your CI server. I have used a build step for this and used &lt;a href=&quot;https://chocolatey.org/&quot;&gt;Chocolatey&lt;/a&gt; to manage the package installation.&lt;/li&gt;
  &lt;li&gt;Before running your build step add another step which calls &lt;em&gt;SonarQube.Scanner.MSBuild.exe begin&lt;/em&gt; so SonarQube can setup hooks into your projects build process. Using the script above might be a good starting point.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;After the build process is completed end your SonarQube scan. This can be done with:&lt;br /&gt;
    &amp;gt; &lt;em&gt;SonarQube.Scanner.MSBuild.exe end&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;During the end step the SonarQube scanner will upload a report to the SonarQube server and your projects dashboard will be updated.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And that is it! Well almost…&lt;/p&gt;

&lt;h3 id=&quot;setting-up-a-project-guid&quot;&gt;Setting Up a Project Guid&lt;/h3&gt;

&lt;p&gt;For SonarQube to recognise your project from other projects it needs an identifier. The development team decided to use the ProjectGuid property in your .csproj file. You might not have one as they are not required by default. So double check your csproj files and update them to include a ProjectGuid property. If you miss this you will see the following error in your CI logs:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;i class=&quot;mark error_msg &quot;&gt;WARNING: The following projects do not have a valid ProjectGuid and were not built using a valid solution (.sln) thus will be skipped from analysis…&lt;/i&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you see that warning add your ProjectGuid!&lt;/p&gt;</content><author><name>Thomas Shipley</name></author><category term=".NET Core" /><category term="CI" /><category term="qa" /><category term="SonarQube" /><summary type="html">Static analysis is a way of automatically analysing code without executing it. As a development team, this is really powerful as once the static analysis software is up, running and integrated with your deployment pipelines you can gain an extra tester in your team with little ongoing maintenance! While some of the issues static analysis software finds are not always high value (code styling for example) some are issues your engineers are less likely to notice such as obscure security flaws and out of date dependencies.</summary></entry><entry><title type="html">Contract Testing with Pact in .NET Core</title><link href="/.net%20core/c%23/contract%20testing/pact/test/2018/03/13/contract-testing-with-pact-in-net-core.html" rel="alternate" type="text/html" title="Contract Testing with Pact in .NET Core" /><published>2018-03-13T17:07:18+00:00</published><updated>2018-03-13T17:07:18+00:00</updated><id>/.net%20core/c%23/contract%20testing/pact/test/2018/03/13/contract-testing-with-pact-in-net-core</id><content type="html" xml:base="/.net%20core/c%23/contract%20testing/pact/test/2018/03/13/contract-testing-with-pact-in-net-core.html">&lt;p&gt;When working in a microservice architecture it can be hard to verify the whole system end to end due to all the moving parts involved. Often the purported solution to this is to write integration tests which verify a couple bits of the system at the same time with the test mocked out. If all these subsections of the system pass their respective integration tests we can be confident in the system, right?&lt;/p&gt;

&lt;h1 id=&quot;the-problem-with-integration-tests&quot;&gt;The Problem with Integration Tests&lt;/h1&gt;

&lt;p&gt;Integration tests are a good way of verifying our system as they use real (not mocked out) components but quite a lot can go wrong. Integration tests are:&lt;/p&gt;

&lt;h2 id=&quot;unstable&quot;&gt;Unstable&lt;/h2&gt;

&lt;p&gt;Much like the end to end tests, integration tests take a lot of effort to keep up to date and are often flakey and unstable. And &lt;a href=&quot;https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html&quot;&gt;unstable tests are worse than no tests&lt;/a&gt; as they train your team to ignore test results.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/2018/03/bad_test_report.png&quot; alt=&quot;Example of Bad Test Report with Flaky Tests&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;broadly-scoped--unspecific&quot;&gt;Broadly Scoped &amp;amp; Unspecific&lt;/h2&gt;

&lt;p&gt;Think about when you are writing some code - one of the first design practices you might have learnt is to keep scope tight. For example, if the code in a loop needs the variable then declare it in there so the code outside of the loop cannot access that variable. That way if the code has a bug in the looping section you know that variable can only have been modified by code within the loop.&lt;/p&gt;

&lt;p&gt;A tight scope should also apply to your tests. When your tests fail you should be able to quickly pinpoint where the failure happened quickly and start to understand why. This is why developers and QAs love unit tests as they are specific and tightly scoped when unit tests fail you typically know exactly why and how to go about developing a fix. This isn’t the case with integration tests when they fail it could be a whole host of things! Perhaps it is the first service, maybe the third? What about datastores did we mock them out? Were those mocks correct?&lt;/p&gt;

&lt;h2 id=&quot;speed&quot;&gt;Speed&lt;/h2&gt;

&lt;p&gt;Integration tests are just slow. It is slow to spin up the subset of your system under test. It is slow to run the tests against the system under test. If you want speed in your test suite the integration tests won’t help.&lt;/p&gt;

&lt;h2 id=&quot;expensive&quot;&gt;Expensive&lt;/h2&gt;

&lt;p&gt;All that time trying to keep your integration tests up to date and fast comes at a cost. Developers or QAs will need to spend quite a lot of time keeping the tests green - in the same way, they keep the end to end tests green.&lt;/p&gt;

&lt;h1 id=&quot;an-alternative-contract-testing&quot;&gt;An Alternative: Contract Testing&lt;/h1&gt;

&lt;p&gt;Instead of creating unstable, broadly scoped, slow and expensive integration tests there is an alternative, contract testing. Contract testing works in a different way to integration testing. Instead of testing real interactions of a subset of the system contract tests generally work by thinking of a data provider and a data consumer:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The Providing API has a suite of unit tests referred to as &lt;em&gt;contract tests&lt;/em&gt; which test that for different API calls to itself the API returns the expected data.&lt;/li&gt;
  &lt;li&gt;The Consuming APIs don’t have integration tests with the Providing API instead they &lt;strong&gt;trust(!)&lt;/strong&gt; that the Providing API will return the data as they expect it. That they will honour the contract they have with the consumer API.&lt;/li&gt;
  &lt;li&gt;As long as the Providing API keeps there contract tests up to date and _communicates _with the teams looking after the Consuming APIs everything will be fine.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;nice-but-unrealistic&quot;&gt;Nice But Unrealistic&lt;/h2&gt;

&lt;p&gt;The three steps above are &lt;strong&gt;idealistic&lt;/strong&gt;. Even with the best intentions providing API teams will struggle to keep consuming API teams up to date. What is needed is a way for the teams to keep themselves up to date as much as possible using inter-team interaction to talk about changes they discover themselves.&lt;/p&gt;

&lt;h1 id=&quot;more-realistic-contract-testing-pactio&quot;&gt;More Realistic Contract Testing: Pact.io&lt;/h1&gt;

&lt;p&gt;Instead of relying on teams to keep each other up to date what if the computer did most of the work. This is the problem that the &lt;a href=&quot;https://docs.pact.io/&quot;&gt;Pact.io&lt;/a&gt; testing framework solves which makes contract testing more realistic. Pact follows an updated flow:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The Consuming API has a suite of component tests referred to as _pact tests _which use Pact for mocking out calls to the Providing API. Once the test run is completed a &lt;strong&gt;PactFile &lt;/strong&gt;is created. This is a JSON record of all the mocked out requests and responses the Consuming API made to the Provider API.&lt;/li&gt;
  &lt;li&gt;The Providing API has a suite of unit tests which consume this PactFile generated by the Consuming API and replay the requests against itself and check the responses match the actual responses from the Providing API.&lt;/li&gt;
  &lt;li&gt;If the Providing API’s pact tests fail that teams build goes red and then they can speak to the Consuming API team to see what mocks they are using and if they are correct or not.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now communication is driven by failing tests and it is the Consuming API team which are driving the tests for the Providing API team. This approach makes it much more likely that the Providing API team will speak to the Consuming API team as without speaking to them about changes and updates for there testing the Providing API pact tests will fail and there build will break.&lt;/p&gt;

&lt;h1 id=&quot;pact-test-implementation-with-net-core&quot;&gt;Pact Test Implementation with .NET Core&lt;/h1&gt;

&lt;p&gt;Pact has been implemented in many languages including .NET Core by the &lt;a href=&quot;https://github.com/pact-foundation/pact-net&quot;&gt;Pact-Net&lt;/a&gt; project on Github! So you can start to write pact tests on your .NET Core projects. To get started you can check their examples and if you are ready to check out my &lt;a href=&quot;https://github.com/tdshipley/pact-workshop-dotnet-core-v1&quot;&gt;Workshop on Github&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;learn-more&quot;&gt;Learn More&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=-6x6XBDf9sQ&quot;&gt;Verifying Microservice Integrations with Contract Testing&lt;/a&gt; (Video)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.pact.io/faq/convinceme.html&quot;&gt;Pact Docs: Convince Me!&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://prezi.com/kb3peundqja5/edit/#0&quot;&gt;Contract Testing with Pact&lt;/a&gt; (Prezi)&lt;/li&gt;
&lt;/ol&gt;</content><author><name>Thomas Shipley</name></author><category term=".NET Core" /><category term="C#" /><category term="contract testing" /><category term="pact" /><category term="Test" /><summary type="html">When working in a microservice architecture it can be hard to verify the whole system end to end due to all the moving parts involved. Often the purported solution to this is to write integration tests which verify a couple bits of the system at the same time with the test mocked out. If all these subsections of the system pass their respective integration tests we can be confident in the system, right?</summary></entry></feed>