I have the following code
public bool IsUnitAvailable()
{
this.isUnitAvailable = false;
if(isUnitAvailable == false)
{
var exception = new Exception("Unit Unavailable");
exception.Data.Add("Quotation","1234567");
exception.Data.Add("propertyDate", "2016-10-10"); this.GetElmahExtensionWrapper().LogToElmah(exception);
}
}
return this.isUnitAvailable;
}
and the following unit test.
[TestMethod]
public void WhenUnitIsNotAvailableExceptionShouldBeLoggedInElmahTest()
{
//Arrange
var iPricingServiceMock = new Mock<IPricingService>(MockBehavior.Strict);
iPricingServiceMock.Setup(
counter => counter.IsUnitAvailableOn(It.IsAny<Unit>(),It.IsAny<DateTime>())).Returns(false);
var mockElmahExtensionWrapper = TestHelper.mk.GetMock<IElmahExtensionWrapper>();
// act
var quotation = new Quotation();
quotation.SetElmahExtensionWrapper(mockElmahExtensionWrapper.Object);
quotation.IsUnitAvailable();
//assert
mockElmahExtensionWrapper.Verify(counter => counter.LogToElmah(It.IsAny<Exception>()), Times.Exactly(1));
//change the test to verify that the exception that was logged had 2 Data properties?
}
The unit test is working. How can I change the test to verify that the exception that was logged had 2 Data properties? Changing the code to the following throws a "Cannot resolve symbol Data property" error.
mockElmahExtensionWrapper.Verify
(
counter => counter.LogToElmah
(
It.IsAny<Exception>(ex=>ex.Data.Count == 2)
),
Times.Exactly(1)
);
Change the verification to something like:
mockElmahExtensionWrapper.Verify(counter => counter.LogToElmah(It.Is<TraceException>(ex => ex.Data["Quotation"] == "1234567" && ex.Data["propertyDate"] == "2016-10-10"), Times.Exactly(1));
Related
I want to write a unit test below method.
Using this method I can add a user and this is works fine. user can be saved.
public async Task<UserModel> SaveAsync(UserModel model)
{
if (string.IsNullOrEmpty(model.ExternalUserId))
{
var extUser = await identityManagementService.CreateUser(model);
user = new ApplicationUser()
{
ExternalUserId = extUser.UserId,
IsActive = true,
UserName = model.Email,
};
user.Id = Guid.NewGuid();
var exists = false;
await applicationUserRepository.AddOrUpdateAsync(user, a => exists);
}
await applicationUserRepository.SaveAsync();
var IsSaved = await identityManagementService.GetUserById(user.ExternalUserId); // to check the user is saved
return model;
}
unit test
[Fact]
public async Task SaveAsync_Should_AddORUpdate_WhenExternalUserIdDoesNOtExsitsAndProfileImgIsNull() // userRole is exist
{
var userModel = UserMockData.UserCorrectModelWithExternalUsserIdEmpty();
var applicationRole = UserMockData.ApplicationRole();
_identityManagementService.Setup(x => x.CreateUser(userModel)).Returns(Task.FromResult(UserMockData.User()));
// _identityManagementService.Setup(x => x.GetUserById(userModel.ExternalUserId)).Returns(() => null);
_applicationRoleRepository.Setup(x => x.FindAsync(userModel.RoleId)).Returns(Task.FromResult(applicationRole));
_identityManagementService.Setup(x => x.AssignUserRoles(It.Is<String>(g => g != String.Empty), applicationRole.ExternalRoleId)).Returns(Task.FromResult(true));
var sut = new UserManagementService(
_applicationRoleRepository.Object,
_applicationUserRepository.Object,
_applicationRolePermissionRepository.Object,
_identityManagementService.Object,
_smtpEmailService.Object,
_logger.Object
);
// Act
var result = await sut.SaveAsync(userModel);
//Asset
result.Should().NotBeNull();
var x = _identityManagementService.Object.GetUserById(userModel.ExternalUserId).Result; // this is null
var y = _applicationRoleRepository.Object.ListAsync(false).Result?.Count(); // this is also null
x.Should().Be(1);
}
When I check the method in debugging mode
var IsSaved = await identityManagementService.GetUserById(user.ExternalUserId); // to check the user is saved this line is not null.
But when I checked unit test debug mode,
var IsSaved = await identityManagementService.GetUserById(user.ExternalUserId); // to check the user is saved is null
How can I verify/test the user is saved by this method?
Please guide me.
Because you have not mock the GetUserById method. You have to mock the GetUserById method. In mock we are not doing actual creation that's why your GetUserById is giving result as null.
Please add below code in your test method -
_identityManagementService.Setup(x => x.GetUserById(userModel.ExternalUserId)).Returns(true);
I'm a big fan of TestCases because they make it trivial to test more edge cases, and the anti-testers seem happier with fewer lines of testing code. I've always struggled with exception testing though.
In my code I have a validation function that checks if there is 1 and only 1 instance in the config. If there are 0 I throw a KeyNotFoundException, and if there's more than 1 a AmbiguousMatchException.
private void ThrowIfNotInConfig(string endpointRef)
{
var count = _config.Endpoints?.Count(x => x.Ref.Equals(endpointRef)) ?? 0;
if (count == 0)
{
throw new KeyNotFoundException($"{nameof(ThrowIfNotInConfig)} - " +
$"No Endpoint in appSettings with the ref {endpointRef}");
}
if (count > 1)
{
throw new AmbiguousMatchException($"{nameof(ThrowIfNotInConfig)} - " +
$"More than 1 Endpoint in appSettings with the ref {endpointRef}");
}
}
Is there a way I can avoid splitting these into 2 separate tests, just because of the exception type, that's neater than this? I don't like doing a try catch in a test, and I feel there should be a way to test against the Exception, like ExpectedException used to.
[TestCase(0, ExpectedResult = "KeyNotFoundException")]
[TestCase(2, ExpectedResult = "AmbiguousMatchException")]
public string ThrowIfNotInConfig_GIVEN_NotASingleEndpointInConfig_THEN_ThrowError(int configOccurrences)
{
// Arrange
const string endpointRef = "ABC";
var config = _validConfig;
config.Endpoints.RemoveAll(x => x.Ref == endpointRef);
config.Endpoints
.AddRange(Enumerable.Range(0, configOccurrences)
.Select(x => new MiraklEndpointConfig { Ref = endpointRef })
);
_config.Setup(c => c.Value).Returns(config);
var service = new URLThrottlingService(_mockLogger.Object, _config.Object);
try
{
// Act
service.IsOKToCallEndpoint(endpointRef);
}
catch (Exception exception)
{
return exception.GetType().Name;
}
return "";
}
Thanks to canton7 and Olimasters answer, I now have this, which is what I was after
[TestCase(0, typeof(KeyNotFoundException))]
[TestCase(2, typeof(AmbiguousMatchException))]
public void ThrowIfNotInConfig_GIVEN_NotASingleEndpointInConfig_THEN_ThrowError(int configOccurrences, Type exception)
{
// Arrange
const string endpointRef = "ABC";
var config = _validConfig;
config.Endpoints.RemoveAll(x => x.Ref == endpointRef);
config.Endpoints
.AddRange(Enumerable.Range(0, configOccurrences)
.Select(x => new MiraklEndpointConfig { Ref = endpointRef })
);
_config.Setup(c => c.Value).Returns(config);
var service = new URLThrottlingService(_mockLogger.Object, _config.Object);
// Act / Assert
Assert.Throws(exception, () => service.IsOKToCallEndpoint(endpointRef));
}
I have to unit test a function (SendMessageNetSkyToAgenceGrp), and inside this function there is a service that I want to mock (EnvoyerNotificationSms.SendMessageNetSky(signalRMessage)):
Here is the code i want to test :
public void SendMessageNetSkyToAgenceGrp(
int agenceId,
string message,
string name,
bool addAgenceLibInMsg = true,
SignalRMessageThemeEnum theme = SignalRMessageThemeEnum.Information)
{
Agence agence = AgenceCoreService.GetAgenceById(agenceId);
if (agence == null || (string.IsNullOrEmpty(agence.Libelle) && addAgenceLibInMsg))
{
return;
}
string finalMessage = (message + (addAgenceLibInMsg ? agence.Libelle : ""));
string groupName = string.Empty;
if (theme == SignalRMessageThemeEnum.NotificationSms)
{
groupName = SignalRConstantes.GRP_SMSAGENCE + SignalRConstantes.SEPARATOR + agenceId;
}
else
{
groupName = (SignalRConstantes.GRP_AGENCE + SignalRConstantes.SEPARATOR + agenceId);
}
SignalRMessage signalRMessage = new SignalRMessage(name, "", finalMessage, groupName, theme);
EnvoyerNotificationSms.SendMessageNetSky(signalRMessage);
}
And here is the test code:
[Fact(DisplayName = "Vérifier l'appel à l'infra IEnvoyerNotificationSms")]
public void SendMessageNetSkyToAgenceGrp_CasNormal_ResultatOk()
{
// Arange
var envoyerNotificationSmMock = new Mock<IEnvoyerNotificationSms>();
envoyerNotificationSmMock.Setup(envoyerNotifSms => envoyerNotifSms.SendMessageNetSky(It.IsAny<SignalRMessage>())).Verifiable();
var SignalRCoreService = LocalIocManager.Resolve<ISignalRCoreService>();
// Act
LocalIocManager.IocContainer.UseInstance(envoyerNotificationSmMock.Object, IfAlreadyRegistered.Replace);
SignalRCoreService.SendMessageNetSkyToAgenceGrp(56, "testMessage", "name", true, SignalRMessageThemeEnum.NotificationSms);
// Assert
envoyerNotificationSmMock.Verify(envoyerNotifSms => envoyerNotifSms.SendMessageNetSky(It.IsAny<SignalRMessage>()), Times.Once());
}
But when I execute the test I get an error telling me that the service I want to mock is null (EnvoyerNotificationSms.SendMessageNetSky(signalRMessage);)
The error is : 'Object reference not set to an instance of an object.' in the line EnvoyerNotificationSms.SendMessageNetSky(signalRMessage);
How can I solve this issue?
After checking the problem was the order of these lines :
var SignalRCoreService = LocalIocManager.Resolve<ISignalRCoreService>();
// Act
LocalIocManager.IocContainer.UseInstance(envoyerNotificationSmMock.Object, IfAlreadyRegistered.Replace);
In the second line has no effect, because the service i want to mock is already created in the first line. So the solution was to change the order of the two lines.
I'm trying to write tests for an Automatonymous state machine, but I'm having a fair bit of trouble getting it right, and I've found very little documentation.
Here's what I have at the moment for one test:
[TestFixture]
public class MyProcessStateMachineTests
{
InMemoryTestHarness _Harness;
MyProcessStateMachine _Machine;
StateMachineSagaTestHarness<MyProcess, MyProcessStateMachine> _Saga;
[OneTimeSetUp]
public void ConfigureMessages()
{
MessageCorrelation.UseCorrelationId<RequestMyDetails>(x => x.CorrelationId);
MessageCorrelation.UseCorrelationId<FileAttached>(x => x.CorrelationId);
MessageCorrelation.UseCorrelationId<PDFGenerated>(x => x.CorrelationId);
MessageCorrelation.UseCorrelationId<CustomerAttachFile>(x => x.CorrelationId);
MessageCorrelation.UseCorrelationId<AddCustomerNote>(x => x.CorrelationId);
MessageCorrelation.UseCorrelationId<EmailPublished>(x => x.CorrelationId);
}
[SetUp]
public void InitializeTestHarness()
{
_Harness = new InMemoryTestHarness();
_Machine = new MyProcessStateMachine( /* snip */ );
_Saga = _Harness.StateMachineSaga<MyProcess, MyProcessStateMachine>(_Machine);
_Harness.Start().Wait();
}
[TearDown]
public void StopTestHarness()
{
_Harness.Stop();
}
[Test]
public async Task ShouldAttachToCustomer()
{
var sagaId = Guid.NewGuid();
var custId = Guid.NewGuid();
var fileAttached = BuildFileAttachedMessage(sagaId);
await _Harness.InputQueueSendEndpoint.Send(BuildStartMessage(sagaId));
await _Harness.InputQueueSendEndpoint.Send(BuildDetailsReceivedMessage(sagaId));
await _Harness.InputQueueSendEndpoint.Send(BuildPdfGeneratedMessage(sagaId));
await _Harness.InputQueueSendEndpoint.Send(fileAttached);
// Next line is based on [the answer here][1]
// Once the above messages are all consumed and processed,
// the state machine should be in AwaitingEmail state
await _Saga.Match(x =>
x.CorrelationId == sagaId
&& x.CurrentState == _Machine.AwaitingEmail.Name,
new TimeSpan(0, 0, 30));
// Grab the instance and Assert stuff...
}
// Snip...
}
Given that the _Saga.Match call finds a match, I would expect that all messages have been processed and I should be able to grab my state machine instance and published events and check their values - but that isn't the case. When I run the tests in the fixture, sometimes the instance I get has consumed and published the expected messages; sometimes it's not quite there yet.
I've tried grabbing my instance using:
var inst = _Saga.Sagas.FirstOrDefault(x => x.Saga.CorrelationId == sagaId);
or grabbing published events with:
var test = _Harness.Published
.FirstOrDefault(x => x.MessageType == typeof(IAttachFile) && x.Context.CorrelationId == sagaId);
but it doesn't matter that the call to Match succeeded, the state machine instance (and published events) aren't always present.
I'm assuming that the async proccesses from Automatonymous, MassTransit, or test harness is causing the inconsistency. Any help?
Testing with MassTransit, MassTransit.Automatonymous and MassTransit.TestFramework 5.1.2.1528, Automatonymous 4.1.1.102,
EDIT:
Further review, I've found that when I have a problem, the call to Match( ... )
didn't succeed - it timed out. (I had been incorrectly assuming that a timeout would throw an exception.)
For anyone hitting the same issue: the way you try to get the instance
var inst = _Saga.Sagas.FirstOrDefault(x => x.Saga.CorrelationId == sagaId);
can be fixed like this
var instanceIds = await _sagaHarness.Match(
instance => instance.CorrelationId == sagaId
&& instance.CurrentState == _machine.Working.Name,
new TimeSpan(0, 0, 30));
It is important that the expected state is included in the condition. Just fetching the instance by correlationid and then testing CurrentState may fail, as setting state (saga execution being async) may take some time.
See full example at https://github.com/balintn22/AutomatonymousTestExample
In case this might be helpful to someone else, this is how I eventually got it working:
[TestFixture]
public class ProcessStateMachineTests : InMemoryTestFixture
{
TimeSpan _TestTimeout = new TimeSpan(0, 1, 0);
ProcessStateMachine _Machine;
InMemorySagaRepository<Process> _Repository;
protected override void ConfigureInMemoryReceiveEndpoint(
IInMemoryReceiveEndpointConfigurator configurator)
{
_Machine = new ProcessStateMachine();
_Repository = new InMemorySagaRepository<Process>();
configurator.StateMachineSaga(_Machine, _Repository);
}
[OneTimeSetUp]
public void ConfigureMessages()
{
// Message correlation and such happens in here
ProcessStateMachine.ConfigureMessages();
}
[Test]
public async Task OnInitializationIStartProcessIsConsumed()
{
var sagaId = Guid.NewGuid();
var customerId = Guid.NewGuid();
await SetupStateMachine(sagaId, customerId, _Machine.AwaitingDetails.Name);
var msg = InMemoryTestHarness.Consumed
.Select<IStartProcess>(x => x.Context.Message.RequestId == sagaId)
.FirstOrDefault();
// Assert against msg for expected results
}
[Test]
public async Task OnStartProcessAddCustomerNoteAndRequestDetailsPublished()
{
var sagaId = Guid.NewGuid();
var customerId = Guid.NewGuid();
await SetupStateMachine(sagaId, customerId, _Machine.AwaitingDetails.Name);
var pubdNoteAddedMsg = InMemoryTestHarness.Published
.Select<IAddCustomerNote>()
.FirstOrDefault(x => x.Context.Message.RequestId == sagaId);
var pubdDetailsReqdMsg = InMemoryTestHarness.Published
.Select<IRequestDetails>()
.FirstOrDefault(x => x.Context.Message.RequestId == sagaId);
Assert.IsTrue(pubdNoteAddedMsg != null);
Assert.IsTrue(pubdDetailsReqdMsg != null);
Assert.AreEqual(sagaId, pubdNoteAddedMsg.Context.CorrelationId);
Assert.AreEqual(sagaId, pubdDetailsReqdMsg.Context.CorrelationId);
Assert.AreEqual(customerId, pubdNoteAddedMsg.Context.Message.CustomerId);
Assert.IsFalse(String.IsNullOrEmpty(pubdNoteAddedMsg.Context.Message.Note));
}
private async Task SetupStateMachine(
Guid sagaId,
Guid customerId,
String toState)
{
if (String.IsNullOrEmpty(toState))
return;
await MoveStateMachineForward(BuildStartMessage(), x => x.AwaitingDetails);
var awaitingDetailsId = await _Repository.ShouldContainSagaInState(
sagaId, _Machine, x => x.AwaitingDetails, _TestTimeout);
Assert.IsNotNull(awaitingDetailsId, "Error, expected state machine in AwaitingDetails state");
if (toState == _Machine.AwaitingDetails.Name)
return;
// ...and more stuff to move to later states, depending on
// where I want my test's starting point to be...
async Task MoveStateMachineForward<T>(
T message,
Func<ProcessStateMachine, Automatonymous.State> targetState)
where T : class
{
await InputQueueSendEndpoint.Send(message);
var foundSagaId = await _Repository.ShouldContainSagaInState(
sagaId, _Machine, targetState, _TestTimeout);
Assert.IsTrue(foundSagaId.HasValue);
}
IStartProcess BuildStartMessage()
{
return new StartProcessMessage(sagaId, customerId);
}
}
}
Why the below assertion is not working?
Code:
[Test]
public void CreateNewTemplateTest()
{
OnlineSignupModel model = new OnlineSignupModel
{
SalesRepId = 68,
PriceAdvanced = (decimal)22.33,
PriceComplete = (decimal)44.33,
PriceMvr = (decimal)6.33,
SetupFee = (decimal)2.33,
};
Assert.That(model, Has.Exactly(5).Items);
}
Error:
System.ArgumentException : The actual value must be an IEnumerable
Parameter name: actual
at NUnit.Framework.Constraints.ExactCountConstraint.ApplyTo[TActual](TActual actual)
at NUnit.Framework.Assert.That[TActual](TActual actual, IResolveConstraint expression, String message, Object[] args)
at NUnit.Framework.Assert.That[TActual](TActual actual, IResolveConstraint expression)
I am trying to assert that there are 5 properties in the object.
You are asserting incorrectly with the wrong constraint.
There are multiple ways to assert the model, but here is one.
[Test]
public void CreateNewTemplateTest() {
//Arrange
var salesRepId = 68,
var priceAdvanced = (decimal)22.33,
var priceComplete = (decimal)44.33,
var priceMvr = (decimal)6.33,
var setupFee = (decimal)2.33,
//Act
OnlineSignupModel model = new OnlineSignupModel {
SalesRepId = salesRepId,
PriceAdvanced = priceAdvanced,
PriceComplete = priceComplete,
PriceMvr = priceMvr,
SetupFee = setupFee,
};
//Assert
Assert.That(
model.SalesRepId = salesRepId &&
model.PriceAdvanced == priceAdvanced &&
model.PriceComplete == priceComplete &&
model.PriceMvr == priceMvr &&
model.SetupFee == setupFee, Is.True);
}
Consider reviewing the docs on how to use the framework
NUnit Documentation Wiki
Avoiding any commentary on the usefulness of this task, to assert that your model has exactly 5 properties, you can use something like Assert.That(typeof(model).GetProperties().Length == 5);