Validation of submitEntities Method does not run when mocked at unit testing - c#

I'm working on a legacy project which is created with .NET Framework 4.8, locator pattern, and business factory to instantiate businesses.
I'm trying to add unit tests using MSTest and MOQ.
The SubmitEntities method in mocked business does not run validations. I mean when I run a test that is expected to throw an exception, it passes successfully. I have no idea why is this happening.
Also, I don't have experience in writing unit tests and this is my first time.
In short, I'm expecting to get exception when the test is run, but it finishes with submittedBalanceMappings with a count of more than zero.
The test class constructor is:
private readonly BalanceMappingBusinessService _balanceMappingBusinessService;
private readonly Mock<IBalanceMappingBusiness> _mockBalanceMappingBusiness = new Mock<IBalanceMappingBusiness>();
public BalanceMapping()
{
_balanceMappingBusinessService = new BalanceMappingBusinessService(_mockBalanceMappingBusiness.Object);
}
The test is:
[TestMethod]
public async Task SubmitEntities_NoDataWillBeSubmitted_IfColumnSettingIdDoesNotExist()
{
// Arrange
await LoginWithSuperAdminAccount();
var submittingBalanceMappings = new List<BalanceMappingEntity>
{
new BalanceMappingEntity
{
AdjustedBalanceDetailId = adjutedBalanceDetailId,
ColumnSettingId = Guid.NewGuid(),
EntityState = EntityState.Added
}
};
var submittedBalanceMappings = new List<BalanceMappingEntity>();
_mockBalanceMappingBusiness.Setup(
bmb => bmb.SubmitEntities(submittingBalanceMappings))
.Callback((List<BalanceMappingEntity> balanceMappings) => submittedBalanceMappings.AddRange(balanceMappings));
var adjutedBalanceDetailId = GetAdjustedBalanceDetail();
//Act
_balanceMappingBusinessService.SubmitEntities(submittingBalanceMappings );
// Assert
Assert.IsTrue(submittedBalanceMappings.Count == 0);
}
The SubmitEntities method is:
public void SubmitEntities(List<BalanceMappingEntity> balanceMappings)
{
try
{
ValidateSubmittingBalanceMappings(balanceMappings);
using var onlineUnitOfWork = new OnlineUnitOfWork();
foreach (var balanceMapping in balanceMappings)
{
balanceMapping.AccountId = ReusableObjects.Current.CurrentAuthenticatedAccountId;
onlineUnitOfWork.Submit(balanceMapping);
}
onlineUnitOfWork.SaveChanges();
}
catch (Exception ex)
{
throw ex;
}
}

Related

Moq doesn't match methods. Moq.MockException: All invocations on the mock must have a corresponding setup

Moq doesn't match the mocked method.
Exception:
Exception thrown: 'Moq.MockException' in Moq.dll:
'IMongoRepository.FindByVrcId("b4cb3139-90aa-4477-979b-d893e3317386")
invocation failed with mock behavior Strict. All invocations on the
mock must have a corresponding setup.'
This is my unit test:
public class OfferHandlerTest : TestBase
{
Mock<IMongoRepository> repositoryMock = new Mock<IMongoRepository>(MockBehavior.Strict);
OfferHandler? offerHandler;
[Fact]
public void HandleTest()
{
JObject? offerFullDocument = null;
using (var sr = new StreamReader("Data/offer_full_document.json"))
{
var reader = new JsonTextReader(sr);
offerFullDocument = JObject.Load(reader);
}
var kafkaPayload = new KafkaMessagePayloadSourceConnector();
kafkaPayload.OperationType = Constants.Mongo_OperationType_Update;
kafkaPayload.FullDocument = offerFullDocument;
OfferService service = new OfferService(repositoryMock.Object);
offerHandler = new OfferHandler(service, this.ServiceConfiguration);
offerHandler.Handle(kafkaPayload);
DHOffer offer = new DHOffer();
offer.Version = 1;
// THIS SETUP FAILS
repositoryMock.Setup(s => s.FindByVrcId<DHOffer>(It.IsAny<string>())).Returns(It.IsAny<DHOffer>());
repositoryMock.Verify(s => s.FindAndUpdate<DHOffer>(It.IsAny<DHOffer>()), Times.Once);
}
}
This is the handle method:
public void Handle(KafkaMessagePayloadSourceConnector kafkaPayload)
{
VRCOffer offer = kafkaPayload!.FullDocument!.ToObject<VRCOffer>()!;
if (kafkaPayload!.OperationType!.Equals(Constants.Mongo_OperationType_Update))
{
offerService.updateOfferStatus(OfferMapper.MapToDataHubModel(offer), offer.MasterId);
}
}
And finally the service method:
public class OfferService
{
private readonly IMongoRepository offerRepository;
public OfferService(IMongoRepository offerRepository)
{
this.offerRepository = offerRepository;
}
internal void updateOfferStatus(DHOffer offer, string vrcMasterId)
{
// THIS SHOULD RETURN MOCKED OBJECT
DHOffer existingOffer = offerRepository.FindByVrcId<DHOffer>(vrcMasterId);
existingOffer.ModifiedDate = DateTime.Now.ToString();
existingOffer.AdditionalInformation.Status = offer?.AdditionalInformation?.Status!;
offerRepository.FindAndUpdate(existingOffer);
}
}
I tried using It.IsAny<DHOffer>() in the Return() method but I get the same exception.
Your issue is that you are running the Moq setup after the mocked object has been used. By then it's already too late. You just need to run the .Setup(...) commands at the start.
It's also worth noting that using a shared mock can be problematic if multiple tests need the setups to be different. Some tools can run tests in parallel which may screw things up, or in a different order which can cause things to be more brittle.

I'm using mock for tests using nunit but it doesn't enter the method

I am testing my viewModel which contains a method that comes from a dependency injection, but does not enter the method, I honestly do not know what I am doing wrong.
my test.
[TestCase("5")]
[TestCase("10")]
[TestCase("-1")]
[TestCase("0")]
[TestCase("100")]
//[TearDown]
[Test]
public async Task Deve_Obter_A_Lista_De_Herois_Dado_A_Quantidade_Menor_Ou_Igual_A_100_E_Maior_Que_Zero(string quantidadeHerois)
{
//Arrang
var mockRepo = new Mock<IHeroes>();
ListHeroesViewViewModel listHeroesViewViewModel = new ListHeroesViewViewModel(null, mockRepo.Object);
//action
await listHeroesViewViewModel.GetHeroes(quantidadeHerois);
//assert
if(quantidadeHerois.Equals("5"))
Assert.AreEqual(5, listHeroesViewViewModel.Herois.Count);
else if (quantidadeHerois.Equals("10"))
Assert.AreEqual(10, listHeroesViewViewModel.Herois.Count);
else
Assert.AreEqual(100, listHeroesViewViewModel.Herois.Count);
}
my viewmodel
public async Task GetHeroes(string limit)
{
try
{
IsBusy = true;
///
////in this point it does not enter the method and returns null////
///
var heroes = await _heroes.GetHeroes(limit);
if (heroes.data != null)
Herois = new ObservableCollection<Result>(heroes.data.results);
}
catch (Exception ex)
{
await App.Current.MainPage.DisplayAlert("Atenção", $"Error:{ex.Message}", "Ok");
}
finally
{
IsBusy = false;
}
}
constructor viewModel
public ListHeroesViewViewModel(INavigationService navigationService, IHeroes heroes) : base(navigationService)
{
_navigation = navigationService;
//
///here he receives the dependency caused by mock.object
//
_heroes = heroes;
Title = "Heroes";
}
I don't know what I could be doing wrong, thank you for understanding this is my first test
By default a mock will return default values, which means for class types you get null.
If you want to return something you need to set it up.
Here is an example of a setup that is saying whenever something calls method GetHeroes return new Hero().
var mockRepo = new Mock<IHeroes>();
mockRepo.Setup(x => x.GetHeroes(It.IsAny<string>())).Returns(new Hero());
This is a simple setup, you can make it as complex as you want.
You can find more info here on how mocking works.

AWS CreateBatchWrite unit test

I'm trying to write some unit test around AWS DynamoDb C# library, CreateBatchWrite.
This is the method:
public void BatchSave<T>(string tableName, List<T> items)
{
if (string.IsNullOrWhiteSpace(tableName))
{
throw new ArgumentNullException(nameof(tableName));
}
if (items == null)
{
throw new ArgumentNullException(nameof(items));
}
items.RemoveAll(x => x == null);
BatchWrite<T> batch = _dynamoDbContext.CreateBatchWrite<T>(
new DynamoDBOperationConfig()
{
OverrideTableName = tableName
});
batch.AddPutItems(items);
batch.Execute();
}
What I want to test are my precondition
_dynamoDbContext is injected and it's an interface (IDynamoDBContext)
My problem is the return object from CreateBatchWrite: BatchWrite is a strongly typed class.
Apart from moving my preconditions one layer below or above, is there any way of unit testing this? Is my approach correct?
If you only want to test preconditions then create an instance of the class under test, pass arguments that will cause the expected behavior and assert that it happens as expected.
There is no need to even mock the dependency if it is not needed for the test to be exercised to completion.
For example
[TestClass]
public class AwsTests {
[Test]
public void Should_Throw_For_Null_TableName() {
//Arrange
var subject = new SubjectUnderTest(null);
ArgumentNullException exception = null;
var expected = "tableName";
//Act
try {
subject.BatchSave<object>(null, null);
} catch (ArgumentNullException e) {
exception = e;
}
//Assert
exception.Should().NotBeNull();
exception.ParamName.Should().Be(expected);
}
[Test]
public void Should_Throw_For_Null_Items() {
//Arrange
var subject = new SubjectUnderTest(null);
ArgumentNullException exception = null;
var expected = "items";
//Act
try {
subject.BatchSave<object>("fakeTableName", null);
} catch (ArgumentNullException e) {
exception = e;
}
//Assert
exception.Should().NotBeNull();
exception.ParamName.Should().Be(expected);
}
}
The above tests the two if conditions of the method as isolation unit tests by providing only what is necessary for the test to be safely exercised to completion.

Moq with Task await

Since I have converted my WCF methods to Async, my unit tests have failed, and I can't figure out the correct syntax to get them to work.
Cllient proxy class
public interface IClientProxy
{
Task DoSomething(CredentialDataList credentialData, string store);
}
service class
public class CredentialSync : ICredentialSync
{
private ICredentialRepository _repository;
private IClientProxy _client;
public CredentialSync()
{
this._repository = new CredentialRepository();
this._client = new ClientProxy();
}
public CredentialSync(ICredentialRepository repository, IClientProxy client)
{
this._repository = repository;
this._client = client;
}
public async Task Synchronise(string payrollNumber)
{
try
{
if (string.IsNullOrEmpty(payrollNumber))
{
.... some code
}
else
{
CredentialDataList credentialData = new CredentialDataList();
List<CredentialData> credentialList = new List<CredentialData>();
// fetch the record from the database
List<GetCredentialData_Result> data = this._repository.GetCredentialData(payrollNumber);
var pinData = this._repository.GetCredentialPinData(payrollNumber);
// get the stores for this employee
var storeList = data.Where(a => a.StoreNumber != null)
.GroupBy(a => a.StoreNumber)
.Select(x => new Store { StoreNumber = x.Key.ToString() }).ToArray();
var credential = this.ExtractCredentialData(data, pinData, payrollNumber);
credentialList.Add(credential);
credentialData.CredentialList = credentialList;
foreach (var store in storeList)
{
//this line causes an Object reference not set to an instance of an object error
await _client.DoSomething(credentialData, store.StoreNumber);
}
}
}
catch (Exception ex)
{
throw new FaultException<Exception>(ex);
}
}
Test Class
/// </summary>
[TestClass]
public class SynchTest
{
private Mock<ICredentialRepository> _mockRepository;
private Mock<IClientProxy> _mockService;
[TestInitialize]
public void Setup()
{
... some setups for repository which work fine
}
[TestMethod]
public async Task SynchroniseData_WithOneEmployee_CallsReplicateService()
{
this._mockService = new Mock<IClientProxy>();
this._mockService.Setup(x=>x.DoSomething(It.IsAny<CredentialDataList>(), It.IsAny<string>()));
// arrange
string payrollNumber = "1";
CredentialSync service = new CredentialSync(this._mockRepository.Object, this._mockService.Object);
// act
await service.Synchronise(payrollNumber);
// assert
this._mockService.VerifyAll();
}
The error is when ClientProxy.DoSomething is called:
Object reference not set to an instance of an object
The parameters are both fine.
If I convert my ClientProxy.DoSomething method to a synchronous method
(public void DoSomething(...) )the code works fine, but I do need this to be called asynchronously
DoSomething returns null instead of returning a Task, and so you get an exception when awaiting it. You need to specify when building the mock that it should return a Task.
In this case it seems that you can simply return an already completed task using Task.FromResult so the mock setup should look like this:
this._mockService.Setup(...).Returns(Task.FromResult(false));
Beginning with the next version of .Net (4.6) you can use Task.CompletedTask like this:
this._mockService.Setup(...).Returns(Task.CompletedTask);
You can reduce the amount of clutter in the code by using ReturnsAsync
this._mockService.Setup(...).ReturnsAsync(false);
This way you can remove the Task.FromResult part of the code
I think you need to return the Task from the DoSomething mock
this._mockService.Setup(x => x.DoSomething(It.IsAny<CredentialDataList>(), It.IsAny<string>()))
.Returns(Task.FromResult<int>(0));

Unit Testing WinForms

I'm new to programming and c#, and have been assigned the task of writing unit tests for legacy code in preparation for big DB change.
The more I read on unit testing, the more skeptical I am on my approach.
How would you approach writting a unit test for the following?
Currently I've just been unit testing my Data Access Layer Methods, ensuring they return back a result? But apparently unit test are supposed to be independent of any outside environments?
How can I test my application, when almost everything is making a call to the database or stored procedure?
My Form Code:
public void button1_Click(object sender, EventArgs e)
{
LoadAllCountries()
}
private static void LoadAllCountries()
{
List<nsHacAppMod.ViewCountryInfo> oReturn = moBusinessServices.GetAllCountries();
}
My Data Access Layer
public List<nsAppMod.ViewCountryInfo> GetAllCountries()
{
List<nsAppMod.ViewCountryInfo> oReturn;
var oResult = from c in moDataContext.ViewCountryInfos
select c;
oReturn = oResult.ToList();
return oReturn;
}
My current unit test for this code, is this acceptable? If not what would you test?
[Test]
public void LoadAllCountries()
{
hac.CatalogSamples cs = new hac.CatalogSamples();
var countries = cs.GetAllCountries().count();
Assert.GreaterOrEqual(countries 0);
}
You can unit test data access things if your context is based off of an interface like IContext it can be faked, and you can then test just the code you are trying to test like the GetAllCountries() method.
However, other than the try catch, there is no actual logic to test. I look at it like this: If it is a property that has no logic in it, or methods too, it's not worth testing.
Using a mocking framework like FakeItEasy I would test this method just like this:
public class ClassToTest
{
internal virtual MoDataContext CreateContext()
{
return new MoDataContext();
}
public List<ViewCountryInfo> GetAllCountries()
{
List<ViewCountryInfo> oReturn = null;
try
{
var oResult = from c in this.CreateContext().ViewCountryInfos
select c;
oReturn = oResult.ToList();
}
catch (Exception)
{
}
return oReturn;
}
[Fact]
public void Test_GetAllCountries_ResultCountShouldBeGreaterThan0()
{
var fakeData = new List<ViewCountryInfo>();
fakeData.Add(new ViewCountryInfo());
var sut = A.Fake<ClassToTest>();
A.CallTo(sut).CallsBaseMethod();
A.CallTo(() => sut.CreateContext()).Returns(fakeData);
var result = sut.GetAllCountries();
Assert.IsTrue(result.Count() > 0);
}

Categories

Resources