In TechTalk SpecFlow, how do I abandon a Scenario? - testing

My scenario reads a file with hundreds of lines. Each line calls an API Service, but the service may not be running. If I get a non-200 response (available inside the 'Then' method), I want to abandon the Scenario & save time.
How can I tell TechTalk SpecFlow to not carry on with the other tests?

You can use a concept like this .
public static FeatureContext _featureContext;
public binding( FeatureContext featureContext)
{
_featureContext = featureContext;
}
[Given(#"user login")]
public void login(){
// do test
bool testPassed = //set based on test. true or false
binding._featureContext.Current["testPass"] = testPassed;
}
Then in BeforeScenario()
[BeforeScenario(Order = 1)]
public void BeforeScenario()
{
Assert.IsTrue(FeatureContext.Current["testPass"];);
}

Related

Spring Integration testing a Files.inboundAdapter flow

I have this flow that I am trying to test but nothing works as expected. The flow itself works well but testing seems a bit tricky.
This is my flow:
#Configuration
#RequiredArgsConstructor
public class FileInboundFlow {
private final ThreadPoolTaskExecutor threadPoolTaskExecutor;
private String filePath;
#Bean
public IntegrationFlow fileReaderFlow() {
return IntegrationFlows.from(Files.inboundAdapter(new File(this.filePath))
.filterFunction(...)
.preventDuplicates(false),
endpointConfigurer -> endpointConfigurer.poller(
Pollers.fixedDelay(500)
.taskExecutor(this.threadPoolTaskExecutor)
.maxMessagesPerPoll(15)))
.transform(new UnZipTransformer())
.enrichHeaders(this::headersEnricher)
.transform(Message.class, this::modifyMessagePayload)
.route(Map.class, this::channelsRouter)
.get();
}
private String channelsRouter(Map<String, File> payload) {
boolean isZip = payload.values()
.stream()
.anyMatch(file -> isZipFile(file));
return isZip ? ZIP_CHANNEL : XML_CHANNEL; // ZIP_CHANNEL and XML_CHANNEL are PublishSubscribeChannel
}
#Bean
public SubscribableChannel xmlChannel() {
var channel = new PublishSubscribeChannel(this.threadPoolTaskExecutor);
channel.setBeanName(XML_CHANNEL);
return channel;
}
#Bean
public SubscribableChannel zipChannel() {
var channel = new PublishSubscribeChannel(this.threadPoolTaskExecutor);
channel.setBeanName(ZIP_CHANNEL);
return channel;
}
//There is a #ServiceActivator on each channel
#ServiceActivator(inputChannel = XML_CHANNEL)
public void handleXml(Message<Map<String, File>> message) {
...
}
#ServiceActivator(inputChannel = ZIP_CHANNEL)
public void handleZip(Message<Map<String, File>> message) {
...
}
//Plus an #Transformer on the XML_CHANNEL
#Transformer(inputChannel = XML_CHANNEL, outputChannel = BUS_CHANNEL)
private List<BusData> xmlFileToIngestionMessagePayload(Map<String, File> xmlFilesByName) {
return xmlFilesByName.values()
.stream()
.map(...)
.collect(Collectors.toList());
}
}
I would like to test multiple cases, the first one is checking the message payload published on each channel after the end of fileReaderFlow.
So I defined this test classe:
#SpringBootTest
#SpringIntegrationTest
#ExtendWith(SpringExtension.class)
class FileInboundFlowTest {
#Autowired
private MockIntegrationContext mockIntegrationContext;
#TempDir
static Path localWorkDir;
#BeforeEach
void setUp() {
copyFileToTheFlowDir(); // here I copy a file to trigger the flow
}
#Test
void checkXmlChannelPayloadTest() throws InterruptedException {
Thread.sleep(1000); //waiting for the flow execution
PublishSubscribeChannel xmlChannel = this.getBean(XML_CHANNEL, PublishSubscribeChannel.class); // I extract the channel to listen to the message sent to it.
xmlChannel.subscribe(message -> {
assertThat(message.getPayload()).isInstanceOf(Map.class); // This is never executed
});
}
}
As expected that test does not work because the assertThat(message.getPayload()).isInstanceOf(Map.class); is never executed.
After reading the documentation I didn't find any hint to help me solved that issue. Any help would be appreciated! Thanks a lot
First of all that channel.setBeanName(XML_CHANNEL); does not effect the target bean. You do this on the bean creation phase and dependency injection container knows nothing about this setting: it just does not consult with it. If you really would like to dictate an XML_CHANNEL for bean name, you'd better look into the #Bean(name) attribute.
The problem in the test that you are missing the fact of async logic of the flow. That Files.inboundAdapter() works if fully different thread and emits messages outside of your test method. So, even if you could subscribe to the channel in time, before any message is emitted to it, that doesn't mean your test will work correctly: the assertThat() will be performed on a different thread. Therefore no real JUnit report for your test method context.
So, what I'd suggest to do is:
Have Files.inboundAdapter() stopped in the beginning of the test before any setup you'd like to do in the test. Or at least don't place files into that filePath, so the channel adapter doesn't emit messages.
Take the channel from the application context and if you wish subscribe or use a ChannelInterceptor.
Have an async barrier, e.g. CountDownLatch to pass to that subscriber.
Start the channel adapter or put file into the dir for scanning.
Wait for the async barrier before verifying some value or state.

JAX-RS Response.getEntity() always null

I need help with Arquillian test.
Add code example of situation.
This code is working ok in real environment. Only in test case made with arquillian the result is not expected
The code:
#Stateless
public class CustomerResourceImpl implements CustomerResource{
#Override
public Response findOne(String id) {
String res = "Un cliente";
return Response.ok(res).build();
}
}
#Path("customer")
#Produces(MediaType.APPLICATION_JSON)
public interface CustomerResource {
#GET
#Path("/findOne")
public javax.ws.rs.core.Response findOne(#QueryParam("id") String id);
}
And this test case
#RunWith(Arquillian.class)
public class CustomerResourceTest {
#Deployment (testable = false)
public static Archive createTestArchive() {
return ShrinkWrap
..... (mas)
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
}
#ArquillianResource
private URL deploymentURL;
#Test
#RunAsClient
public void findOne(#ArquillianResteasyResource CustomerResource resource) throws Exception {
final Response response = resource.findOne("1");
System.out.println(response.getEntity()); // IS NULL ??
System.out.println(response.getStatus()); // 200 OK
assertNotNull(response);
}
}
The problem is that response.getEntity() is always NULL . Why? The status response OK = 200 , it is OK. This service run ok in jboss 7.2 with Java 8.
Thanks!
The reason is #Deployment (testable = false)
#Deployment says:
testable = Defines if this deployment should be wrapped up based on the protocol so the testcase can be executed incontainer.
So false means it will not be deployed in the container, and therefore will be null when your tests run inside the container.
I recommend using #Deployment with not parameters passed in rather than setting testable = true
I just solved this today after a days of fiddling. I think I pasted the #Deployment (testable = false) code from examples on the internet that I didn't understand hoping to get something working.

Spring WebFlux (Flux): how to publish dynamically

I am new to Reactive programming and Spring WebFlux. I want to make my App 1 publish Server Sent event through Flux and my App 2 listen on it continuously.
I want Flux publish on-demand (e.g. when something happens). All the example I found is to use Flux.interval to periodically publish event, and there seems no way to append/modify the content in Flux once it is created.
How can I achieve my goal? Or I am totally wrong conceptually.
Publish "dynamically" using FluxProcessor and FluxSink
One of the techniques to supply data manually to the Flux is using FluxProcessor#sink method as in the following example
#SpringBootApplication
#RestController
public class DemoApplication {
final FluxProcessor processor;
final FluxSink sink;
final AtomicLong counter;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
public DemoApplication() {
this.processor = DirectProcessor.create().serialize();
this.sink = processor.sink();
this.counter = new AtomicLong();
}
#GetMapping("/send")
public void test() {
sink.next("Hello World #" + counter.getAndIncrement());
}
#RequestMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent> sse() {
return processor.map(e -> ServerSentEvent.builder(e).build());
}
}
Here, I created DirectProcessor in order to support multiple subscribers, that will listen to the data stream. Also, I provided additional FluxProcessor#serialize which provide safe support for multiproducer (invocation from different threads without violation of Reactive Streams spec rules, especially rule 1.3). Finally, by calling "http://localhost:8080/send" we will see the message Hello World #1 (of course, only in case if you connected to the "http://localhost:8080" previously)
Update For Reactor 3.4
With Reactor 3.4 you have a new API called reactor.core.publisher.Sinks. Sinks API offers a fluent builder for manual data-sending which lets you specify things like the number of elements in the stream and backpressure behavior, number of supported subscribers, and replay capabilities:
#SpringBootApplication
#RestController
public class DemoApplication {
final Sinks.Many sink;
final AtomicLong counter;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
public DemoApplication() {
this.sink = Sinks.many().multicast().onBackpressureBuffer();
this.counter = new AtomicLong();
}
#GetMapping("/send")
public void test() {
EmitResult result = sink.tryEmitNext("Hello World #" + counter.getAndIncrement());
if (result.isFailure()) {
// do something here, since emission failed
}
}
#RequestMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent> sse() {
return sink.asFlux().map(e -> ServerSentEvent.builder(e).build());
}
}
Note, message sending via Sinks API introduces a new concept of emission and its result. The reason for such API is the fact that the Reactor extends Reactive-Streams and has to follow the backpressure control. That said if you emit more signals than was requested, and the underlying implementation does not support buffering, your message will not be delivered. Therefore, the result of tryEmitNext returns the EmitResult which indicates if the message was sent or not.
Also, note, that by default Sinsk API gives a serialized version of Sink, which means you don't have to care about concurrency. However, if you know in advance that the emission of the message is serial, you may build a Sinks.unsafe() version which does not serialize given messages
Just another idea, using EmitterProcessor as a gateway to flux
import reactor.core.publisher.EmitterProcessor;
import reactor.core.publisher.Flux;
public class MyEmitterProcessor {
EmitterProcessor<String> emitterProcessor;
public static void main(String args[]) {
MyEmitterProcessor myEmitterProcessor = new MyEmitterProcessor();
Flux<String> publisher = myEmitterProcessor.getPublisher();
myEmitterProcessor.onNext("A");
myEmitterProcessor.onNext("B");
myEmitterProcessor.onNext("C");
myEmitterProcessor.complete();
publisher.subscribe(x -> System.out.println(x));
}
public Flux<String> getPublisher() {
emitterProcessor = EmitterProcessor.create();
return emitterProcessor.map(x -> "consume: " + x);
}
public void onNext(String nextString) {
emitterProcessor.onNext(nextString);
}
public void complete() {
emitterProcessor.onComplete();
}
}
More info, see here from Reactor doc. There is a recommendation from the document itself that "Most of the time, you should try to avoid using a Processor. They are harder to use correctly and prone to some corner cases." BUT I don't know which kind of corner case.

Toggling App.Config settings at runtime C#

I am wondering what the best approach to toggling App.Config settings for C# would be. This is involving our test suite, and we would like the option to either choose a remote or local environment to kick the tests off. We use LeanFT and NUnit as our testing framework, and currently in order to get tests to run remote we have to add an <leanft></leanft> config in the App.config file. How can I specify different configurations at run time when I kick these tests off thru the command line? Thanks!
Any leanft configuration can be modified at runtime, by using the SDK namespace or the Report namespace.
Here's an example using NUnit 3 showing how you can achieve this
using NUnit.Framework;
using HP.LFT.SDK;
using HP.LFT.Report;
using System;
namespace LeanFtTestProject
{
[TestFixture]
public class LeanFtTest
{
[OneTimeSetUp]
public void TestFixtureSetUp()
{
// Initialize the SDK
SDK.Init(new SdkConfiguration()
{
AutoLaunch = true,
ConnectTimeoutSeconds = 20,
Mode = SDKMode.Replay,
ResponseTimeoutSeconds = 20,
ServerAddress = new Uri("ws://127.0.0.1:5095") // local or remote, decide at runtime
});
// Initialize the Reporter (if you want to use it, ofc)
Reporter.Init(new ReportConfiguration()
{
Title = "The Report title",
Description = "The report description",
ReportFolder = "RunResults",
IsOverrideExisting = true,
TargetDirectory = "", // which means the current parent directory
ReportLevel = ReportLevel.All,
SnapshotsLevel = CaptureLevel.All
});
}
[SetUp]
public void SetUp()
{
// Before each test
}
[Test]
public void Test()
{
Reporter.ReportEvent("Doing something", "Description");
}
[TearDown]
public void TearDown()
{
// Clean up after each test
}
[OneTimeTearDown]
public void TestFixtureTearDown()
{
// If you used the reporter, invoke this at the end of the tests
Reporter.GenerateReport();
// And perform this cleanup as the last leanft step
SDK.Cleanup();
}
}
}

Grails integration testsuite suite

We have a set of integration test which depend upon same set of static data. Since the amount of data is huge we dont want to set it up per test level. Is it possible to setup data at the start, run group of test and rollback the data at the end of test.
What we effectively want is the rollback at test suite level rather than test case level. We are using grails 1.3.1, any pointers would be highly helpful for us to proceed. Thanks in advance.
-Prakash
for one test case you could use:
#BeforeClass
public static void setUpBeforeClass() throws Exception {
}
#AfterClass
public static void tearDownAfterClass() throws Exception {
}
haven't tried a suite of test cases (yet).
i did have some trouble using findByName in the static methods and had to resort to saving an id and using get.
i did try rolling up a suite, but no joy, getting a: no runnable methods.
You can take control of the transaction/rollback behaviour by marking your test case as non-transactional and managing data, transactions and rollbacks yourself. Example:
class SomeTests extends GrailsUnitTestCase {
static transactional = false
static boolean testDataGenerated = false
protected void setUp() {
if (!testDataGenerated) {
generateTestData()
testDataGenerated = true
}
}
void testSomething() {
...test...
}
void testSomethingTransactionally() {
DomainObject.withTransaction {
...test...
}
}
void testSomethingTransactionallyWithRollback() {
DomainObject.withTransaction { status ->
...test...
status.setRollbackOnly()
}
}
}