Dynamic testing for any camunda bpmn process - testing

I am working on a Camunda java code and i am looking for a testing methodology that i can use to test any of my bpmn processes.
i have made some google search and i found on Camunda documentation some ideas about unit testing but it is do test for a specific bpmn model .
i need one to test any bpmn model (just by passing name of bpmn file and id of process etc)
the strategy should take into account the integration with DB to get candidate (user&group) for any expected path.i know maybe i can't do that but i have a large model and it will be time waste to test all of it in traditional ways.

Mohammad, your question is interesting - this goal can be achieved (test on bpmn can be dynamic), if we talk about not very detailed test.
Look at my code below, written by your idea of such common test (as i understood it, of course)
I use camunda-bpm-assert-scenario and camunda-bpm-assert libs in it.
First of all you gives to your test info about "wait states" in testing process (this can be done by json file - for not to change the code)
// optional - for mocking services for http-connector call, et.c.
private Map<String, Object> configs = withVariables(
"URL_TO_SERVICE", "http://mock-url.com/service"
);
private Map<String, Map<String, Object>> userTaskIdToResultVars = new LinkedHashMap<String, Map<String, Object>>() {{
put("user_task_0", withVariables(
"a", 0
));
put("user_task_1", withVariables(
"var0", "var0Value",
"var1", "var1Value"));
}};
// optional - if you want to check vars during process execution
private Map<String, Map<String, Object>> userTaskIdToAssertVars = new LinkedHashMap<String, Map<String, Object>>() {{
put("user_task_1", withVariables(
"a", 0
));
}};
Then you mocking user tasks (and other wait states) with given info:
#Mock
private ProcessScenario processScenario;
#Before
public void defineHappyScenario() {
MockitoAnnotations.initMocks(this);
for (String taskId : userTaskIdToResultVars.keySet()) {
when(processScenario.waitsAtUserTask(taskId)).thenReturn(
(task) -> {
// optional - if you want to check vars during process execution
Map<String, Object> varsToCheck = userTaskIdToAssertVars.get(taskId);
if (varsToCheck != null) {
assertThat(task.getProcessInstance())
.variables().containsAllEntriesOf(varsToCheck);
}
task.complete(userTaskIdToResultVars.get(taskId));
});
}
// If it needs, we describe mocks for other wait states in same way,
// when(processScenario.waitsAtSignalIntermediateCatchEvent(signalCatchId).thenReturn(...);
}
And your test will be anything like this:
#Test
#Deployment(resources = "diagram_2.bpmn")
public void testHappyPath() {
Scenario scenario = Scenario.run(processScenario).startByKey(PROCESS_DEFINITION_KEY, configs).execute();
ProcessInstance process = scenario.instance(processScenario);
assertThat(process).isStarted();
assertThat(process).hasPassedInOrder( // or check execution order of all elements -- not only wait-states (give them in additional file)
userTaskIdToResultVars.keySet().toArray(new String[0]) // user_task_0, user_task_1
);
assertThat(process).isEnded();
}
Hope this helps in your work.

Related

How to unit test azure function using Xunit and Moq

I am very new to unit tests and recently started learning it from various online resources.
But still it confuses me when I need to implement it in my code.
For the given image which I have attached here, could anyone of you suggest me how should I start or where to start?
This is Azure function which I will be creating unit test for, framework/library I would prefer is Xunit and moq.
As mentioned in a comment, a good place to start when unit testing is looking at your code and identifying the different "paths" it can take and what the result of that path will be.
if (inventoryRequest != null)
{
// path 1
await _inventoryService.ProcessRequest(inventoryRequest);
_logger.LogInformation("HBSI Inventory Queue trigger function processed.");
}
else
{
// path 2
_logger.LogInformation("Unable to process HBSI Rate plan Queue.");
}
In your code, because of your if statement, there are 2 possible paths which will end in 2 different results = 2 unit tests.
Now you can start creating your unit tests but first you need to find out what you need to set up to be able to trigger your code.
private readonly ILogger _logger;
private readonly IInventoryService _inventoryService;
public InventoryServiceBusFunction(ILogger logger, IInventoryService inventoryService)
{
_logger = logger;
_inventoryService = inventoryService;
}
You have some dependencies being passed into your constructor with interfaces - great, this means we can mock them. We want to mock dependencies in unit tests because we want to control their behaviour for the tests. Also, mocking the dependencies negates any "real" behaviour the dependency might be performing i.e. database operations, API calls etc.
Using Moq we can mock the objects like so:
public class InventoryServiceBusFunctionTests
{
private readonly Mock<ILogger> _mockLogger = new Mock<ILogger>();
private readonly Mock<IInventoryService> _mockInventoryService = new Mock<IInventoryService>();
...
We will use these mocks later to make verifications on behaviour we expect to happen.
Next, we need to create an instance of the actual class we want to test.
// using a constructor in the test class will run this code before each test
public InventoryServiceBusFunctionTests()
{
// pass the mocked objects to initialize class
_inventoryServiceBusFunction = new InventoryServiceBusFunction(_mockLogger.Object, _mockInventoryService.Object);
}
Now that we have an instance of the InventoryServiceBusFunction class, we can use any of the public properties/methods in our tests.
[Fact]
public async Task GivenInventoryRequest_WhenFunctionRuns_ThenInventoryServiceProcessesRequest()
{
Now, remembering the paths from earlier, we can start to create the test cases. We can take the first path and create a [Fact] for it. You want to give your test case a meaningful name. I usually use the style of Given_When_Then to describe what is expected to happen.
Next, I usually add 3 comment sections to my test case:
// arrange
// act
// assert
This allows me to clearly see which parts of the test are doing what.
// act
await _inventoryServiceBusFunction.Run(inventoryRequest);
Next, I would fill in the \\ act section because this will tell me (via Intellisense) what I need to arrange. e.g. above, when hovering my mouse over the Run method, I can see that I need to pass an instance of InventoryRequest.
// arrange
var inventoryRequest = new InventoryRequest
{
Name = "abc123",
Quantity = 2,
Tags = new List<string>
{
"foo"
}
};
In the \\ arrange section, initialize an instance of the InventoryRequest class and set the properties. This can be any data as we aren't really interested in the data itself but more what happens when the code runs.
if (inventoryRequest != null)
{
// path 1
await _inventoryService.ProcessRequest(inventoryRequest);
_logger.LogInformation("HBSI Inventory Queue trigger function processed.");
}
Lastly, the \\ assert section. Here, we want to make assertions on what we expect to happen given the set up of the test. So given the InventoryRequest is not null, we expect the if to evaluate to true and we expect the _inventoryService.ProcessRequest(inventoryRequest) method to be executed.
// assert
_mockInventoryService
.Verify(x => x.ProcessRequest(It.Is<InventoryRequest>(ir => ir.Name == inventoryRequest.Name
&& ir.Quantity == inventoryRequest.Quantity
&& ir.Tags.Contains(inventoryRequest.Tags[0]))));
In Moq, we can use the .Verify() method on the mock object to assert that the method was called. We can use the It.Is<T> syntax to make assertions on the data that is passed to the method.
Here is the full test case for path 1:
[Fact]
public async Task GivenInventoryRequest_WhenFunctionRuns_ThenInventoryServiceProcessesRequest()
{
// arrange
var inventoryRequest = new InventoryRequest
{
Name = "abc123",
Quantity = 2,
Tags = new List<string>
{
"foo"
}
};
// act
await _inventoryServiceBusFunction.Run(inventoryRequest);
// assert
_mockInventoryService
.Verify(x => x.ProcessRequest(It.Is<InventoryRequest>(ir => ir.Name == inventoryRequest.Name
&& ir.Quantity == inventoryRequest.Quantity
&& ir.Tags.Contains(inventoryRequest.Tags[0]))));
}
Then for path 2, you are setting up the test so that the else condition is executed.
[Fact]
public async Task GivenInventoryRequestIsNull_WhenFunctionRuns_ThenInventoryServiceDoesNotProcessRequest()
{
// arrange
InventoryRequest inventoryRequest = null;
// act
await _inventoryServiceBusFunction.Run(inventoryRequest);
// assert
_mockInventoryService
.Verify(x => x.ProcessRequest(It.IsAny<InventoryRequest>()), Times.Never);
}
Note - in the \\ assert here, I am asserting that the await _inventoryService.ProcessRequest(inventoryRequest) method is never called. This is because you want the test to fail in this scenario as the method should only be executed in the if condition. You may also choose to verify that the logger method is called with the correct message.

Integration testing with event sourcing systems

I'm working on a PoC where we use CQRS in combination with Event Sourcing. We use the Axon framework and Axon server as toolset.
We have some microservices (Maven packages) with some business logic.
A simple overview of the application flow:
We post a xml message (with REST) to service 1 that will result in an event (with Aggregate).
Service 2 handles the event "fired" by service 1 and starts a saga flow. Part of the sage flow is for example to send a mail message.
I can do some tests with Axon Test to test the aggregate from service 1 or the saga from service 2. But is there a good option to do a real integration test where we start with posting a message to the REST interface and check all the operations in the aggregate and saga (inclusive sending mail and so on)
Maybe this kind of integration test is overdone and it's better to test each component on it's own. I doubt what's needed / the best solution to test this type of system.
I suggest to have a look at testcontainers (https://www.testcontainers.org/)
It provides a very convenient way to start up and cleanly tear down docker containers in JUnit tests. This feature is very useful for integration testing of applications against real databases and any other resource (for example Axon Server) for which a docker image is available (https://hub.docker.com/r/axoniq/axonserver/).
I'm sharing some code snippets from JUnit 4 test class (Kotlin). Hopefully this can help you to get started and evolve your specific test strategy (integration should cover smaller scope then end-to-end tests). My opinion is that integration test should focus on Axon messaging API components and REST API components separately/independently. End-to-end should cover all components in your microservice/s.
#RunWith(SpringRunner::class)
#SpringBootTest
#ContextConfiguration(initializers = [DrestaurantCourierCommandMicroServiceIT.Initializer::class])
internal class DrestaurantCourierCommandMicroServiceIT {
#Autowired
lateinit var eventStore: EventStore
#Autowired
lateinit var commandGateway: CommandGateway
companion object {
// An Axon Server container
#ClassRule
#JvmField
var axonServerTestContainer = KGenericContainer(
"axoniq/axonserver")
.withExposedPorts(8024, 8124)
.waitingFor(Wait.forHttp("/actuator/info").forPort(8024))
.withStartupTimeout(Duration.of(60L, ChronoUnit.SECONDS))
// A PostgreSQL container is being started up using a JUnit Class Rule which gets triggered before any of the tests are run:
#ClassRule
#JvmField
var postgreSQLContainer = KPostgreSQLContainer(
"postgres:latest")
.withDatabaseName("drestaurant")
.withUsername("demouser")
.withPassword("thepassword")
.withStartupTimeout(Duration.of(60L, ChronoUnit.SECONDS))
}
// Pass details on the application as properties BEFORE Spring starts creating a test context for the test to run in:
class Initializer : ApplicationContextInitializer<ConfigurableApplicationContext> {
override fun initialize(configurableApplicationContext: ConfigurableApplicationContext) {
val values = TestPropertyValues.of(
"spring.datasource.url=" + postgreSQLContainer.jdbcUrl,
"spring.datasource.username=" + postgreSQLContainer.username,
"spring.datasource.password=" + postgreSQLContainer.password,
"spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect",
"axon.axonserver.servers=" + axonServerTestContainer.containerIpAddress + ":" + axonServerTestContainer.getMappedPort(8124)
)
values.applyTo(configurableApplicationContext)
}
}
#Test
fun `restaurant command microservice integration test - happy scenario`() {
val who = "johndoe"
val auditEntry = AuditEntry(who, Calendar.getInstance().time)
val maxNumberOfActiveOrders = 5
val name = PersonName("Ivan", "Dugalic")
val orderId = CourierOrderId("orderId")
// ******* Sending the `createCourierCommand` ***********
val createCourierCommand = CreateCourierCommand(name, maxNumberOfActiveOrders, auditEntry)
commandGateway.sendAndWait<Any>(createCourierCommand)
await withPollInterval org.awaitility.Duration.ONE_SECOND atMost org.awaitility.Duration.FIVE_SECONDS untilAsserted {
val latestCourierCreatedEvent = eventStore.readEvents(createCourierCommand.targetAggregateIdentifier.identifier).asStream().toList().last().payload as CourierCreatedEvent
assertThat(latestCourierCreatedEvent.name).isEqualTo(createCourierCommand.name)
assertThat(latestCourierCreatedEvent.auditEntry.who).isEqualTo(createCourierCommand.auditEntry.who)
assertThat(latestCourierCreatedEvent.maxNumberOfActiveOrders).isEqualTo(createCourierCommand.maxNumberOfActiveOrders)
}
// ******* Sending the `createCourierOrderCommand` **********
val createCourierOrderCommand = CreateCourierOrderCommand(orderId, auditEntry)
commandGateway.sendAndWait<Any>(createCourierOrderCommand)
await withPollInterval org.awaitility.Duration.ONE_SECOND atMost org.awaitility.Duration.FIVE_SECONDS untilAsserted {
val latestCourierOrderCreatedEvent = eventStore.readEvents(createCourierOrderCommand.targetAggregateIdentifier.identifier).asStream().toList().last().payload as CourierOrderCreatedEvent
assertThat(latestCourierOrderCreatedEvent.aggregateIdentifier.identifier).isEqualTo(createCourierOrderCommand.targetAggregateIdentifier.identifier)
assertThat(latestCourierOrderCreatedEvent.auditEntry.who).isEqualTo(createCourierOrderCommand.auditEntry.who)
}
// ******* Assign the courier order to courier **********
val assignCourierOrderToCourierCommand = AssignCourierOrderToCourierCommand(orderId, createCourierCommand.targetAggregateIdentifier, auditEntry)
commandGateway.sendAndWait<Any>(assignCourierOrderToCourierCommand)
await withPollInterval org.awaitility.Duration.ONE_SECOND atMost org.awaitility.Duration.FIVE_SECONDS untilAsserted {
val latestCourierOrderAssignedEvent = eventStore.readEvents(assignCourierOrderToCourierCommand.targetAggregateIdentifier.identifier).asStream().toList().last().payload as CourierOrderAssignedEvent
assertThat(latestCourierOrderAssignedEvent.aggregateIdentifier.identifier).isEqualTo(assignCourierOrderToCourierCommand.targetAggregateIdentifier.identifier)
assertThat(latestCourierOrderAssignedEvent.auditEntry.who).isEqualTo(assignCourierOrderToCourierCommand.auditEntry.who)
assertThat(latestCourierOrderAssignedEvent.courierId.identifier).isEqualTo(assignCourierOrderToCourierCommand.courierId.identifier)
}
}
}
class KGenericContainer(imageName: String) : GenericContainer<KGenericContainer>(imageName)
class KPostgreSQLContainer(imageName: String) : PostgreSQLContainer<KPostgreSQLContainer>(imageName)
Axon developers suggest to go with docker solution as mentioned here.
Testcontainers seems to be the best here.
My java snippet:
#ActiveProfiles("test")
public class TestContainers {
private static final int AXON_HTTP_PORT = 8024;
private static final int AXON_GRPC_PORT = 8124;
public static void startAxonServer() {
GenericContainer axonServer = new GenericContainer("axoniq/axonserver:latest")
.withExposedPorts(AXON_HTTP_PORT, AXON_GRPC_PORT)
.waitingFor(
Wait.forLogMessage(".*Started AxonServer.*", 1)
);
axonServer.start();
System.setProperty("ENV_AXON_GRPC_PORT", String.valueOf(axonServer.getMappedPort(AXON_GRPC_PORT)));
}
Call startAxonServer method in your #BeforeClass. Now you have to obtain external docker ports (these indicated in withExposedPorts are docker-internal).
You can do it in runtime via getMappedPort as shown in my snippet. Remember to provide connection configuration to your test suite. My example on spring boot as follows:
axon:
axonserver:
servers: localhost:${ENV_AXON_GRPC_PORT}
Complete working solution can be found on my github project.

How to implement an integration test to check if my circuit breaker fallback is called?

In my application, I need to call an external endpoint and if it is too slow a fallback is activated.
The following code is an example of how my app looks like:
#FeignClient(name = "${config.name}", url = "${config.url:}", fallback = ExampleFallback.class)
public interface Example {
#RequestMapping(method = RequestMethod.GET, value = "/endpoint", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
MyReturnObject find(#RequestParam("myParam") String myParam);
}
And its fallback implementation:
#Component
public Class ExampleFallback implements Example {
private final FallbackService fallback;
#Autowired
public ExampleFallback(final FallbackService fallback) {
this.fallback = fallback;
}
#Override
public MyReturnObject find(final String myParam) {
return fallback.find(myParam);
}
Also, a configured timeout for circuit breaker:
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000
How can I implement an integration test to check if my circuit break is working, i.e, if my endpoint (mocked in that case) is slow or if it returns an error like 4xx or 5xx?
I'm using Spring Boot 1.5.3 with Spring Cloud (Feign + Hystrix)
Note i donot know Feign or Hystrix.
In my opinion it is problematic to implement an automated integrationtest that simulates different implementatondetails of Feign+Hystrix - this implementation detail can change at any time. There are many different types of failure: primary-Endpoint not reachable, illegal data (i.e. receiving a html-errormessage, when exprecting xml data in a special format), disk-full, .....
if you mock an endpoint you make an assumption of implementationdetail of Feign+Hystrix how the endpoint behaves in a errorsituation (i.e. return null, return some specific errorcode, throw an exception of type Xyz....)
i would create only one automated integration test with a real primary-enpoint that has a never reachable url and a mocked-fallback-endpoint where you verify that the processed data comes from the mock.
This automated test assumes that handling of "networkconnection too slow" is the same as "url-notfound" from your app-s point of view.
For all other tests i would create a thin wrapper interface around Feign+Hystrix where you mock Feign+Hystrix. This way you can automatically test for example what happens if you receive 200bytes from primary interface and then get an expetion.
For details about hiding external dependencies see onion-architecture

How do I replace one test in an XML-defined suite with three others in TestNG?

Our team uses TestNG to run some tests in Selenium. We need to be able to run a given test on 3 different browsers (Chrome, Firefox, and [sadly] IE). We have a browser parameter on our base test class and really we could just declare three tests, one each for each browser; however, we'd really like to just be able to specify the browser value as "Standard 3" and have that run the test on each browser automatically.
So, I've built a class that implements ISuiteListener and attempts to create the new tests on the fly. However, any way I try to add tests fails. That is, no new tests I try to add will be executed by the suite. It's like nothing I did actually changed anything.
Here's my code:
public class Standard3BrowserSuiteListener implements ISuiteListener {
#Override
public void onStart(final ISuite suite) {
final XmlSuite xmlSuite = suite.getXmlSuite();
final Map<String, String> suiteParameters = xmlSuite.getParameters();
final List<XmlTest> currentTests = new ArrayList<XmlTest>(xmlSuite.getTests());
final ArrayList<XmlTest> testsToRun = new ArrayList<XmlTest>(currentTests.size());
for (final XmlTest test : currentTests) {
final Browser browser;
final Map<String, String> testParameters = test.getAllParameters();
{
String browserParameter = testParameters.get("browser");
if (browserParameter == null) {
browserParameter = suiteParameters.get("browser");
}
browser = Util.Enums.getEnumValueByName(browserParameter, Browser.class);
}
if (browser == Browser.STANDARD_3) {
XmlTest nextTest = cloneTestAndSetNameAndBrowser(xmlSuite, test, testParameters, "Chrome");
xmlSuite.addTest(nextTest);
testsToRun.add(nextTest); // alternate I've tried to no avail
nextTest = cloneTestAndSetNameAndBrowser(xmlSuite, test, testParameters, "Firefox");
xmlSuite.addTest(nextTest);
testsToRun.add(nextTest); // alternate I've tried to no avail
nextTest = cloneTestAndSetNameAndBrowser(xmlSuite, test, testParameters, "IE");
xmlSuite.addTest(nextTest);
testsToRun.add(nextTest); // alternate I've tried to no avail
} else {
testsToRun.add(test);
}
}
// alternate to xmlSuite.addTest I've tried to no avail
testsToRun.trimToSize();
currentTests = xmlSuite.getTests();
currentTests.clear();
currentTests.addAll(testsToRun);
}
private XmlTest cloneTestAndSetNameAndBrowser(final XmlSuite xmlSuite, final XmlTest test,
final Map<String, String> testParameters, final String browserName) {
final XmlTest nextTest = (XmlTest) test.clone();
final Map<String, String> nextParameters = new TreeMap<String, String>(testParameters);
nextParameters.put("browser", browserName.toUpperCase());
nextTest.setName(browserName);
final List<XmlClass> testClasses = new ArrayList<XmlClass>(test.getClasses());
nextTest.setClasses(testClasses);
return nextTest;
}
#Override
public void onFinish(final ISuite suite) {}
}
How can I replace the test with the browser value "Standard 3" with 3 tests and have it run properly? Thanks!
Here's what you need to do :
Upgrade to the latest released version of TestNG.
Build an implementation of org.testng.IAlterSuiteListener
Move your implementation that you created in ISuiteListener into this listener implementation.
Wire in this listener via the <listeners> tag in your suite XML File (or) via ServiceLoaders (As described in the javadocs of this interface)

How to test service layer which directly uses NHibernate?

Hello can anyone give me advice on how to test my service layer which uses NHibernate ISession directly?
public class UserAccountService : IUserAccountService
{
private readonly ISession _session;
public UserAccountService(ISession session)
{
_session = session;
}
public bool ValidateUser(string email, string password)
{
var value = _session.QueryOver<UserInfo>()
.Select(Projections.RowCount()).FutureValue<int>().Value;
if (value > 0) return true;
return false;
}
}
I opt to use NHibernate directly for simple cases like simple query,validations and creating/updating records in the database. Coz i dont want to have an abstraction like repository/dao layer on top of Nhibernate that will just add more complexity to my architecture.
You need to decide what you want to actually test on your Service Layer, regardless of the fact that you're using NH.
In your example, a good first test might be to test that the email and password that you pass into your service method is actually being used as a check in your session.
In this case, you'd simply need to stub your session variable and set up expectations using a mock framework of some kind (like Rhino Mocks) that would expect a pre-determined email and password, and then return an expected result.
Some pseudocode for this might look like:
void ValidateUser_WhenGivenGoodEmailAndPassword_ReturnsTrue()
{
//arrange
var stubbedSession = MockRepository.GenerateStub<ISession>();
stubbedSession
.Expect(x => x.Query<UserInfo>())
.Return(new List {
new UserInfo { Email = "johns#email.com", Password = "whatever" } });
var service = new UserAccountService(stubbedSession);
//act
var result = service.ValidateUser("johns#email.com", "whatever");
//assert
Assert.That(result, Is.True);
}
I think you'll find it difficult to test database interactions in a static way. I'd recommend delegating responsibilities to another layer (that layer that adds complexity that you mentioned) that can be mocked for testing purposes, if you deem the functionality important enough to test.