Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

How to test incoming and outgoing steps

Mogens Heller Grabe edited this pageJul 29, 2019 ·1 revision

If you are extending Rebus by inserting steps into either the incoming or the outgoing pipelines, you might want to test that those steps work too.

An example could be this step that copies the value of the current principal'shttp://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn claim to an outgoing header:

[StepDocumentation("Sets the 'x-upn' header on outgoing messages to the current user's UPN.")]classSetUsernameOutgoingStep:IOutgoingStep{publicTaskProcess(OutgoingStepContextcontext,Func<Task>next){varupn=ClaimsPrincipal.Current?.FindFirst(ClaimTypes.Upn)?.Value;if(upn!=null){varmessage=context.Load<Message>();varheaders=message.Headers;headers["x-upn"]=upn;}returnnext();}}

While it would certainly be possible to simplynew up the step and exercise it in isolation in a unit test, it's much more interesting to see if it works in conjunction with all the other steps in the pipeline, so we create an integration test for it instead.

In this case, because we're testing an outgoing step, our test should consist of

  • a one-way client configured with our step
  • a message sent to a queue
  • an in-mem network, so we can inspect the sent message

The test could look like this (assuming we're using NUnit):

[Test]publicasyncTaskVerifyUpnHeaderIsSet(){// this is the UPNvarupn=Guid.NewGuid().ToString();// establish identity with UPN claimvarclaimsIdentity=newClaimsIdentity(new[]{newClaim(ClaimTypes.Upn,upn),});ClaimsPrincipal.ClaimsPrincipalSelector=()=>newClaimsPrincipal(claimsIdentity);// create one-way clientusing(varactivator=newBuiltinHandlerActivator()){varnetwork=newInMemNetwork();varbus=Configure.With(activator).Transport(t=>t.UseInMemoryTransportAsOneWayClient(network)).Options(o=>o.Decorate<IPipeline>(c=>{varpipeline=c.Get<IPipeline>();varstep=newSetUsernameOutgoingStep();returnnewPipelineStepInjector(pipeline).OnSend(step,PipelineRelativePosition.Before,typeof(AssignDefaultHeadersStep));})).Options(o=>o.LogPipeline(verbose:true)).Start();// create destination queuenetwork.CreateQueue("dst-queue");// send string message to destination queueawaitbus.Advanced.Routing.Send("dst-queue","hej med dig");// retrieve message that was sentvarmessage=network.GetNextOrNull("dst-queue");Assert.That(message,Is.Not.Null,"Expected to receive a message");Assert.That(message.Headers,Contains.Key("x-upn").And.ContainValue(upn));}}

As you can see, it's slightly more involved this way, but we can now be pretty sure that our step works as intended.

Btw., did you notice the little.Options(o => o.LogPipeline(verbose: true)) thing above? It instructs Rebus to output the contents of its send/receive pipelines to the log, in this case resulting in the following output:

------------------------------------------------------------------------------Message pipelines------------------------------------------------------------------------------Send pipeline:    RebusWikiCodeSamples.SetUsernameOutgoingStep        Sets the 'x-upn' header on outgoing messages to the current        user's UPN.    Rebus.Pipeline.Send.AssignDefaultHeadersStep        Assigns these default headers to the outgoing message:                1) a new GUID as the 'rbs2-msg-id' header (*).                2) a 'rbs2-return-address' (unless the bus is a one-way        client) (*).                3) a 'rbs2-senttime' with the current time.                4) 'rbs2-msg-type' with the message's simple assembly-qualified        type name (*).                (*) Unless explicitly set to something else    Rebus.Pipeline.Send.FlowCorrelationIdStep        Sets the 'rbs2-corr-id' header of the outgoing message        to one of the following three things:                1) The correlation ID of the message currently being handled.        2) The message ID of the message currently being handled.        3) The message's own message ID.    Rebus.Pipeline.Send.AutoHeadersOutgoingStep        If the outgoing message type has [HeaderAttribute(...,        ...)] on it, the found headers will automatically        be picked up and added to the outgoing message.                Headers already on the message will not be overwritten.    Rebus.Pipeline.Send.SerializeOutgoingMessageStep        Serializes the outgoing message using the configured        serializer, storing the resulting transport message back        to the context.    Rebus.Pipeline.Send.ValidateOutgoingMessageStep        Checks the consistency of the outgoing message    Rebus.Pipeline.Send.SendOutgoingMessageStep        Final step that uses the current transport to send the transport        message found in the context to all addresses found by looking        up the DestinationAddress object from the context.Receive pipeline:    Rebus.Retry.Simple.SimpleRetryStrategyStep        Wraps the invocation of the entire receive pipeline in an exception        handler, tracking the number of times the received message        has been attempted to be delivered.                If the maximum number of delivery attempts is reached,        the message is moved to the error queue.    Rebus.Retry.FailFast.FailFastStep        Checks if a message has failed with specific exceptions        and marks it as "failed too many times". This allows the SimpleRetryStrategyStep        to move it to the error queue.    Rebus.Pipeline.Receive.HandleDeferredMessagesStep        If the incoming message should not be handled now, this step        saves the message until it is time to deliver the message.                This is done by checking if the incoming message has a 'rbs2-deferred-until'        header with a desired time to be delivered.    Rebus.DataBus.ClaimCheck.HydrateIncomingMessageStep        Incoming step that 'hydrates' big messages, if the payload        was stored as a data bus attachment.    Rebus.Pipeline.Receive.DeserializeIncomingMessageStep        Deserializes the current transport message using the configured        serializer, saving the deserialized message back to the context.    Rebus.Pipeline.Receive.HandleRoutingSlipsStep        If the message being handled is a routing slip with an itinerary,        this step ensures that the routing slip is forwarded        to the next destination.    Rebus.Pipeline.Receive.ActivateHandlersStep        Looks at the incoming message and decides how to handle        it. A HandlerInvokers object is saved to the context to be        invoked later.    Rebus.Sagas.LoadSagaDataStep        Looks at the handler invokers in the context and sees if there's        one or more saga handlers in there.                If that's the case, relevant saga data is loaded/created,        and the rest of the pipeline gets invoked.                Afterwards, all the created/loaded saga data is updated        appropriately.    Rebus.Pipeline.Receive.DispatchIncomingMessageStep        Gets all the handler invokers from the current context        and invokes them in order.                Please note that each invoker might choose to ignore the invocation        internally.                If no invokers were found, a RebusApplicationException        is thrown.------------------------------------------------------------------------------

We do our best to ensure that the documentation wiki is up-to-date - please let us know if you think there's something we should do better.

Basic stuff

Configuration

Scenarios

Areas

Transports (not a full list)

Customization

Pipelines

Prominent application services

Clone this wiki locally


[8]ページ先頭

©2009-2025 Movatter.jp