Micro-services are the new black; everyone is using them. Alas, when your system is composed of many micro-services, testing becomes more challenging. The straight-forward approach for E2E testing no longer suffices and for integration tests it doesn’t even exist. A better way to test in this kind of an environment would be to work with a test kit of the micro-service you are interacting with.
By the end of this talk, you will learn how to create a test-kit that covers your micro-service. Testing this way will grant you a much higher level of confidence, and will portray a more accurate picture of your assumptions vs. reality. Overall it will make any integration between micro-services easier, thus benefit your colleagues and make your company progress faster.
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
A better approach for testing microservices - introducing test kits in practice
1. A Better Approach for Testing Micro-Services
Introducing: Test Kits in Practice
Maxim Novak, Wix Back-end
https://github.com/maximn@maximnovakmaximn@wix.com
14. Testing with microservices
is challenging.
You still want...
❏ A short and reliable
feedback loop
❏ To test assumptions vs.
reality (logic/protocol)
22. MY APP
STORE
if (isTestMode) {
// ...
}
else {
// ...
}
TEST
USERS
CLIENT
STUB
USERS
CLIENT
SESSION
(USER ID)
CONFIRMATION
PAGE WITH
NAME
Users
SERVER
23. The real
implementation
is never tested
(well … only in
production)
MY APP
STORE
TEST
STUB
USERS
CLIENT
SESSION
(USER ID)
CONFIRMATION
PAGE WITH
NAME
Users
SERVERUSERS
CLIENT
24. You DO want an “out of process
component tests” (e2e).
29. ❏ A short and reliable
feedback loop
❏ To test assumptions vs.
reality (logic/protocol)
✘
BEHAVES AS
WE ASSUME ✔
#1
Run against an
external environment
30. ❏ A short and reliable
feedback loop
❏ To test assumptions vs.
reality (logic/protocol)
✘
ENSURE
COMMUNICATION
PROTOCOL &
SCHEMA
✔
#1
Run against an
external environment
31. Running against external environment is
unreliable. It has a high maintenance
cost and it adds complexity to your app.
35. @Test
public void purchase_e2e() {
UUID userId = UUID.randomUUID();
String name = someName();
fakeUsersServer.givenUser(userId, name);
login(userId);
addItemToCart(itemId);
ConfirmationPage confirmationPage = purchase();
assertThat(confirmationPage, containsName(name));
}
#2
Use test
doubles
E2E
example
36. @Test
public void purchase_e2e() {
UUID userId = UUID.randomUUID();
String name = someName();
fakeUsersServer.givenUser(userId, name);
login(userId);
addItemToCart(itemId);
ConfirmationPage confirmationPage = purchase();
assertThat(confirmationPage, containsName(name));
}
#2
Use test
doubles
E2E
example
37. @Test
public void purchase_e2e() {
UUID userId = UUID.randomUUID();
String name = someName();
fakeUsersServer.givenUser(userId, name);
login(userId);
addItemToCart(itemId);
ConfirmationPage confirmationPage = purchase();
assertThat(confirmationPage, containsName(name));
}
#2
Use test
doubles
E2E
example
38. @Test
public void purchase_e2e() {
UUID userId = UUID.randomUUID();
String name = someName();
fakeUsersServer.givenUser(userId, name);
login(userId);
addItemToCart(itemId);
ConfirmationPage confirmationPage = purchase();
assertThat(confirmationPage, containsName(name));
}
#2
Use test
doubles
E2E
example
39. @Test
public void getName_success() {
UUID userId = UUID.randomUUID();
String name = someName();
fakeUsersServer.givenUser(userId, name);
String result = usersClient.getName(userId);
assertEquals(name, result);
}
#2
Use test
doubles
IT success
example
40. @Test
public void getName_success() {
UUID userId = UUID.randomUUID();
String name = someName();
fakeUsersServer.givenUser(userId, name);
String result = usersClient.getName(userId);
assertEquals(name, result);
}
#2
Use test
doubles
IT success
example
41. @Test
public void getName_success() {
UUID userId = UUID.randomUUID();
String name = someName();
fakeUsersServer.givenUser(userId, name);
String result = usersClient.getName(userId);
assertEquals(name, result);
}
#2
Use test
doubles
IT success
example
42. @Test
public void getName_success() {
UUID userId = UUID.randomUUID();
String name = someName();
fakeUsersServer.givenUser(userId, name);
String result = usersClient.getName(userId);
assertEquals(name, result);
}
#2
Use test
doubles
IT success
example
43. @Test(expected = UserNotFoundException.class)
public void getName_notFound() {
UUID userId = UUID.randomUUID();
fakeUsersServer.givenUserNotFound(userId);
usersClient.getName(userId);
}
#2
Use test
doubles
IT failure
example
44. @Test(expected = UserNotFoundException.class)
public void getName_notFound() {
UUID userId = UUID.randomUUID();
fakeUsersServer.givenUserNotFound(userId);
usersClient.getName(userId);
}
#2
Use test
doubles
IT failure
example
45. @Test(expected = UserNotFoundException.class)
public void getName_notFound() {
UUID userId = UUID.randomUUID();
fakeUsersServer.givenUserNotFound(userId);
usersClient.getName(userId);
}
#2
Use test
doubles
IT failure
example
46. @Test(expected = UserNotFoundException.class)
public void getName_notFound() {
UUID userId = UUID.randomUUID();
fakeUsersServer.givenUserNotFound(userId);
usersClient.getName(userId);
}
#2
Use test
doubles
IT failure
example
47. #2
Use test
doubles
❏ A short and reliable
feedback loop
❏ To test assumptions vs.
reality (logic/protocol)
✔
48. #2
Use test
doubles
❏ A short and reliable
feedback loop
❏ To test assumptions vs.
reality (logic/protocol)
✔
✔✘
WE IMPLEMENT THE
TEST DOUBLE IN A
WAY WE ASSUME IT
WORKS - NOT HOW IT
WORKS IN REALITY
51. We can do
better.
HAVE A MUCH
HIGHER LEVEL
OF CONFIDENCE
❏ A short and reliable
feedback loop
❏ To test assumptions vs.
reality (logic/protocol)
✔
✔
54. @Test
public void purchase_e2e() {
UUID userId = UUID.randomUUID();
String name = someName();
User user = new UsersTestBuilder()
.withId(userId)
.withName(name)
.build();
usersTestkit.givenUser(user);
login(userId);
addItemToCart(itemId);
ConfirmationPage confirmationPage = purchase();
assertThat(confirmationPage, containsName(name));
}
#3
Test kits
E2E
example
55. @Test
public void purchase_e2e() {
UUID userId = UUID.randomUUID();
String name = someName();
User user = new UsersTestBuilder()
.withId(userId)
.withName(name)
.build();
usersTestkit.givenUser(user);
login(userId);
addItemToCart(itemId);
ConfirmationPage confirmationPage = purchase();
assertThat(confirmationPage, containsName(name));
}
#3
Test kits
E2E
example
56. @Test
public void purchase_e2e() {
UUID userId = UUID.randomUUID();
String name = someName();
User user = new UsersTestBuilder()
.withId(userId)
.withName(name)
.build();
usersTestkit.givenUser(user);
login(userId);
addItemToCart(itemId);
ConfirmationPage confirmationPage = purchase();
assertThat(confirmationPage, containsName(name));
}
#3
Test kits
E2E
example
57. @Test
public void purchase_e2e() {
UUID userId = UUID.randomUUID();
String name = someName();
User user = new UsersTestBuilder()
.withId(userId)
.withName(name)
.build();
usersTestkit.givenUser(user);
login(userId);
addItemToCart(itemId);
ConfirmationPage confirmationPage = purchase();
assertThat(confirmationPage, containsName(name));
}
#3
Test kits
E2E
example
58. @Test
public void getName_success() {
UUID userId = UUID.randomUUID();
String name = someName();
User givenUser = new UsersTestBuilder()
.withId(userId)
.withName(name)
.build();
usersTestkit.givenUser(givenUser);
String result = usersClient.getName(userId);
assertEquals(name, result);
}
#3
Test kits
IT success
example
59. @Test
public void getName_success() {
UUID userId = UUID.randomUUID();
String name = someName();
User givenUser = new UsersTestBuilder()
.withId(userId)
.withName(name)
.build();
usersTestkit.givenUser(givenUser);
String result = usersClient.getName(userId);
assertEquals(name, result);
}
#3
Test kits
IT success
example
60. @Test
public void getName_success() {
UUID userId = UUID.randomUUID();
String name = someName();
User givenUser = new UsersTestBuilder()
.withId(userId)
.withName(name)
.build();
usersTestkit.givenUser(givenUser);
String result = usersClient.getName(userId);
assertEquals(name, result);
}
#3
Test kits
IT success
example
61. @Test
public void getName_success() {
UUID userId = UUID.randomUUID();
String name = someName();
User givenUser = new UsersTestBuilder()
.withId(userId)
.withName(name)
.build();
usersTestkit.givenUser(givenUser);
String result = usersClient.getName(userId);
assertEquals(name, result);
}
#3
Test kits
IT success
example
65. public class UsersTestkit {
public void start(int port) {
...
}
public void stop() {
...
}
...
What the
consumer
gets?
66. public class UsersTestkit {
...
public void givenUser(User user) {
...
}
public void updateUser(UUID userId,
UserUpdate user) {
...
}
}
What the
consumer
gets?
69. You’re able to
communicate with
your consumers
Other services
Use test doubles
Database
Implement in-memory version
Cross-test with the real
implementation
WHEN SOMETHING
CHANGES - THEY KNOW
ABOUT IT
OUR
MICRO
SERVICE
70. What about next level
dependencies?
Other services
Use test doubles
Database
Implement in-memory version
Cross-test with the real
implementation
OUR TESTKIT WON’T
BRING MORE LEVELS
IN THE CHAIN OF
SERVICES!
OUR
MICRO
SERVICE
71. Integration Contract
Test
We want to make sure that our
testkit behaves like the real thing
OUR
MICRO
SERVICE
https://martinfowler.com/bliki
/IntegrationContractTest.html