I have the method below I will like to unit test. I am using mstest. Notice how CatService
is used to call 2 other methods
This line of code gets a service of Type T
_provider.GetNecessaryService<IJohnsonProject>() gets a service of Type T
Here is the method
public async Task<(bool, string)> AddDataAsync(DataDto firstSet)
{
try
{
var CatService = _provider.GetNecessaryService<IJohnsonProject>();
var dto = _mapper.Map<MyDto>(firstSet);
var reply = await CatService.AddInfoAsync(dto);
if (!string.IsNullOrEmpty(firstSet.ImageMime) && firstSet.Image.Length > 0)
{
await CatService.AddPictureAsync(reply.Id, firstSet.Image, firstSet.ImageMime);
}
return (true, reply.Id);
}
catch (Exception ex)
{
return (false, ex.Message);
}
}
I started thinking I have to write some Mocks. The first one I have below should return a service type of T
[TestMethod]
public async Task MyFirstTest(){
var CatService = _mockprovider.Setup(x => x.GetNecessaryService<IJohnsonProject>());
}
What is the best way to Mock these two lines ?
var reply = await CatService.AddInfoAsync(dto);
await CatService.AddPictureAsync(reply.Id, firstSet.Image, firstSet.ImageMime);
_provider is a factory pattern, therefore you need to implement a mocked up version of the objects that it returns too:
var mockedJohnsonProject = new Mock<IJohnsonProject>();
mockedJohnsonProject.Setup(x=>x.AddInfoAsync(It.IsAny<MyDto>());
var CatService = _mockprovider.Setup(x => x.GetNecessaryService<IJohnsonProject>())
.Returns(mockedJohnsonProject.Object);
Related
This question it's about ABP framework implementation of DDD,in the Domain layer there a class named "Entity"Manager, this class is a factory for the domain entity and have the method CreateAsync for entity instantiation. I want to reuse this method (or a better approach) to update my entity without redoing the same logic on Application layer. This is the method on AporteManager.
public async Task<Aporte> CreateAsync(
AporteValidation valid
)
{
var icontaBancaria = await _contaBancariaRepository.WithDetailsAsync(
x => x.Banco, x => x.FonteDeRecurso, x => x.CodigoDeAplicacao, x => x.Fundo, x => x.FonteDeRecursoSICONFI);
var contaBancaria = icontaBancaria.Where(x => x.Id == valid.ContaBancariaId).FirstOrDefault();
valid.FonteDeRecursoId = contaBancaria.FonteDeRecurso?.Id;
valid.CodigoDeAplicacaoId = contaBancaria.CodigoDeAplicacao?.Id;
return new Aporte(
valid
);
}
And this is my update method on Application:
[Authorize(ContabilidadePermissions.Aporte.Edit)]
public async Task UpdateAsync(int id, CreateUpdateAporteDto input)
{
try
{
var aporte = await _aporteRepository.GetAsync(id);
if (aporte is not null)
{
var validation = ObjectMapper.Map<CreateUpdateAporteDto, AporteValidation>(input);
var aporteValidado = await _aporteManager.CreateAsync(validation);
aporte = ObjectMapper.Map(aporteValidado, aporte);
await _aporteRepository.UpdateAsync(aporte);
//aporte = ObjectMapper.Map(input, aporte);
//await _aporteRepository.UpdateAsync(aporte);
}
else
{
throw new EntidadeNaoExisteParaSerAtualizadaException();
}
}
catch (Exception ex)
{
throw new RegistroJaExisteGenericoException("Aporte", "Código");
}
}
Although UpdateAsync is not working, I'm not just looking to a solution, but a correct, maintainable and simple DDD solution. Here is a sample of the project: https://github.com/heitorgiacominibrasil/DomainManager
you must see the tutorials in the docs.abp.io
https://docs.abp.io/en/abp/latest/Tutorials/Part-6?UI=MVC&DB=Mongo
AuthorManager: The Domain Service
https://docs.abp.io/en/abp/latest/Tutorials/Part-6?UI=MVC&DB=Mongo#authormanager-the-domain-service
Here is my unit test method
[Fact]
public void DealerSmsStatusTestTest_MustReturnInternalServerErrorIfMockMethodFails()
{
//Arrange
Mock<DBClass.IDealer> mock = new Mock<DBClass.IDealer>();
var exception = FormatterServices.GetUninitializedObject(typeof(System.Data.SqlClient.SqlException));
mock.Setup(x => x.GetDealerStatus(new System.Net.Http.HttpRequestMessage()))
.Throws((System.Data.SqlClient.SqlException)exception);
DealerSettingController controller = new DealerSettingController(mock.Object);
//Act
var result = controller.DealerSmsStatus();
//Assert
/*I will do assertion here*/
}
And here is my controller method
public IHttpActionResult DealerSmsStatus()
{
try
{
var result = _dealer.GetDealerStatus(Request);
return Json(new Models.Response(
Models.ResponseMessages.Success,
result)
);
}
catch (System.Data.SqlClient.SqlException)
{
return InternalServerError();
}
catch (System.Exception ex)
{
Logger.Error(ex, ex.Message, ex.StackTrace);
return InternalServerError();
}
}
When i debug the test, GetDealerStatus() method should return SqlException instead it returns null. In controller method var result always getting null. Any suggestions appreciated why it is not working.I want to throw SqlException through GetDealerStatus().
Here is debug mode result value image
You should use It.IsAny<System.Net.Http.HttpRequestMessage>() instead of new System.Net.Http.HttpRequestMessage() at Setup. Because you configured your method for concrete instance of System.Net.Http.HttpRequestMessage, at test it's not the same.
It's probably the matcher x.GetDealerStatus(new System.Net.Http.HttpRequestMessage())
new System.Net.Http.HttpRequestMessage() creates a new instance of a HttpRequestMessage which will not be equal to the Request you're passing into GetDealerStatus in your SUT.
Normally you'd use something like:
x.GetDealerStatus(It.IsAny<System.Net.Http.HttpRequestMessage>())
or
It.Is<System.Net.Http.HttpRequestMessage>(x => whatever specific equality conditions you want to match on)
if you want to narrow the match condition from just 'any'
I am new to TAP and async/await in practice in C# so I may have some bad code smells here, so be gentle. :-)
I have a service method that looks as follows:
public OzCpAddOrUpdateEmailAddressToListOutput AddOrUpdateEmailAddressToList(
OzCpAddOrUpdateEmailAddressToListInput aParams)
{
var result = new OzCpAddOrUpdateEmailAddressToListOutput();
try
{
var mailChimManager = new MailChimpManager(aParams.MailChimpApiKey);
Task<Member> mailChimpResult =
mailChimManager.Members.AddOrUpdateAsync(
aParams.Listid,
new Member
{
EmailAddress = aParams.EmailAddress
});
//Poll async task until it completes.
//Give it at most 8 seconds to do what it needs to do
var outOfTime = DateTime.Now.AddSeconds(8);
while (!mailChimpResult.IsCompleted)
{
if (DateTime.Now > outOfTime)
{
throw new Exception("Timed out waiting for MailChimp API.");
}
}
//Should there have been a problem with the call then we raise an exception
if (mailChimpResult.IsFaulted)
{
throw new Exception(
mailChimpResult.Exception?.Message ??
"Unknown mail chimp library error.",
mailChimpResult.Exception);
}
else
{
//Call to api returned without failing but unless we have
//the email address subscribed we have an issue
if (mailChimpResult.Result.Status != Status.Subscribed)
{
throw new Exception(
$"There was a problem subscribing the email address
{aParams.EmailAddress} to the mailchimp list id
{aParams.Listid}");
}
}
}
catch (Exception ex)
{
result.ResultErrors.AddFatalError(PlatformErrors.UNKNOWN, ex.Message);
}
return result;
}
But when I call in from MVC Controller action mailChimpResult.IsCompleted always returns false and eventually I hit the timeout.
I realise this is because I am not chaining the async calls as per HttpClient IsComplete always return false and because of different threads this behaviour is "expected".
However I want my service method to hide the complexity of the async nature of what it is doing and merely do what appears to be a synchronous call in my action method namely:
var mailChimpResult =
_PlatformMailChimpService.AddOrUpdateEmailAddressToList(
new OzCpAddOrUpdateEmailAddressToListInput
{
EmailAddress = aFormCollection["aEmailAddress"],
Listid = ApplicationSettings.Newsletter.MailChimpListId.Value,
MailChimpApiKey = ApplicationSettings.Newsletter.MailChimpApiKey.Value
});
if (mailChimpResult.Result == true)
{
//So something
}
Ideally you should avoid the .Result and .IsFaulted properties of the Task and Task<T> objects, that was code smell number one. When you're using these objects you should use async and await through the entire stack. Consider your service written this way instead:
public async Task<OzCpAddOrUpdateEmailAddressToListOutput>
AddOrUpdateEmailAddressToList(
OzCpAddOrUpdateEmailAddressToListInput aParams)
{
var result = new OzCpAddOrUpdateEmailAddressToListOutput();
try
{
var mailChimManager = new MailChimpManager(aParams.MailChimpApiKey);
Member mailChimpResult =
await mailChimManager.Members.AddOrUpdateAsync(
aParams.Listid,
new Member
{
EmailAddress = aParams.EmailAddress
});
}
catch (Exception ex)
{
result.ResultErrors.AddFatalError(PlatformErrors.UNKNOWN, ex.Message);
}
return result;
}
Notice that I was able to remove all of that unnecessary polling and examining of properties. We mark the method as Task<OzCpAddOrUpdateEmailAddressToListOutput> returning and decorate it with the async keyword. This allows us to use the await keyword in the method body. We await the .AddOrUpdateAsync which yields the Member.
The consuming call into the service looks similar, following the same paradigm of async and await keywords with Task or Task<T> return types:
var mailChimpResult =
await _PlatformMailChimpService.AddOrUpdateEmailAddressToList(
new OzCpAddOrUpdateEmailAddressToListInput
{
EmailAddress = aFormCollection["aEmailAddress"],
Listid = ApplicationSettings.Newsletter.MailChimpListId.Value,
MailChimpApiKey = ApplicationSettings.Newsletter.MailChimpApiKey.Value
});
if (mailChimpResult.Result == true)
{
//So something
}
It is considered best practice to postfix the "Async" word to the method, to signify that it is asynchronous, i.e.; AddOrUpdateEmailAddressToListAsync.
I am trying to figure out what I am missing here. My test runs fine but my MOQ VerifyAll is throwing an exception.
[TestMethod]
public async Task ActionPlanDataProvider_GetActionPlanReferenceList_ReturnsValid()
{
try
{
//Arrange
Mock<IActionPlanDataProvider> moqAPlan = new Mock<IActionPlanDataProvider>();
//moqAPlan.Setup(x => x.GetActionPlanReferenceList()).ReturnsAsync(new ActionPlanReferenceList());
moqAPlan
.Setup(x => x.GetActionPlanReferenceList("1"))
.Returns(Task.FromResult(new ActionPlanReferenceList()));
//Act
var d = await moqAPlan.Object.GetActionPlanReferenceList("1234123");
//Assert
moqAPlan.VerifyAll();
}
catch (Exception ex)
{
string a = ex.Message;
throw;
}
}
The following setups were not matched...
I'm wondering if this is because the way async runs that my MOQ doesn't see mocked object method call?
That happens when the Setup is not used. You set up the mock to use GetActionPlanReferenceList("1") but called GetActionPlanReferenceList("1234123").
So according to moq what you executed didn't match what you setup.
You could either match the expected arguments or try
moqAPlan
.Setup(x => x.GetActionPlanReferenceList(It.IsAny<string>()))
.Returns(Task.FromResult(new ActionPlanReferenceList()));
which will let the method accept any string vai the It.IsAny<string>() expression argument
I am using Moq as my mocking framework and I need to test a class that when a specific type of exception is run it will keep trying until the situation is resolved once that happens the execution finishes.
So what I need is something similar to:
myMock = Mock<IFoo>();
myMock.Setup(m => m.Excecute()).Throws<SpecificException>();
myMock.Setup(m => m.Execute());
var classUnderTest = MyClass(myMock);
classUnderTest.DoSomething();
Assert.AreEqual(expected, classUnderTest.Result);
Thanks for any help you can give.
This is one way, based on the Moq QuickStart example of returning different values on each invocation.
var mock = new Mock<IFoo>();
var calls = 0;
mock.Setup(foo => foo.GetCountThing())
.Returns(() => calls)
.Callback(() =>
{
calls++;
if (calls == 1)
{
throw new InvalidOperationException("foo");
}
});
try
{
Console.WriteLine(mock.Object.GetCountThing());
}
catch (InvalidOperationException)
{
Console.WriteLine("Got exception");
}
Console.WriteLine(mock.Object.GetCountThing());
If the method returns void, use:
var myMock = new Mock<IFoo>();
bool firstTimeExecuteCalled = true;
myMock.Setup(m => m.Execute())
.Callback(() =>
{
if (firstTimeExecuteCalled)
{
firstTimeExecuteCalled = false;
throw new SpecificException();
}
});
try
{
myMock.Object.Execute();
}
catch (SpecificException)
{
// Would really want to call Assert.Throws instead of try..catch.
Console.WriteLine("Got exception");
}
myMock.Object.Execute();
Console.WriteLine("OK!");
https://github.com/Moq/moq4/wiki/Quickstart#miscellaneous
Setting up a member to return different values / throw exceptions on sequential calls:
var mock = new Mock<IFoo>();
mock.SetupSequence(f => f.GetCount())
.Returns(3) // will be returned on 1st invocation
.Returns(2) // will be returned on 2nd invocation
.Returns(1) // will be returned on 3rd invocation
.Returns(0) // will be returned on 4th invocation
.Throws(new InvalidOperationException()); // will be thrown on 5th invocation
Why not actually write your own test object that does this? If it's just going to be used for testing ie something like:
public class Mock : IFoo
{
private int _calls;
public Mock()
{
_calls = 0;
}
public int Execute()
{
_calls++;
if (_calls == 1)
throw new Exception();
return value;
}
}