I try to test my custom RepositoryHub which inherits base class Hub (implements IHub interface). I mocked all necessary properties of IHub and one his method call which i want to test. Method call was imitated as call from derived custom class RepositoyHub:
hubMock.Setup(p => p.OnConnected()).Returns(new RepositoryHub().OnConnected());
The problem is that method don't have access to mocked IHub fields.
[TestMethod]
public void Is_OnConnected_Successive_When_Instances_is_Absent_And_User_Authenticated()
{
try
{
var connectionId = "1";
var request = new Mock<IRequest>();
request.Setup(s => s.User.Identity.Name).Returns(user + "&" + server + "&" + password + "&" + level);
request.Setup(s => s.User.Identity.IsAuthenticated).Returns(true);
var mockClients = new Mock<IHubCallerConnectionContext>();
var mockGroupManager = new Mock<IGroupManager>();
var mockHubCallerContext = new Mock<HubCallerContext>(request.Object, connectionId);
var hubMock = new Mock<IHub>();
hubMock.Setup(p => p.Groups).Returns(mockGroupManager.Object);
hubMock.Setup(p => p.Context).Returns(mockHubCallerContext.Object);
hubMock.Setup(p => p.Clients).Returns(mockClients.Object);
//Mock virtual method call
hubMock.Setup(p => p.OnConnected()).Returns(new RepositoryHub().OnConnected());
var r = hubMock.Object.OnConnected();
}
catch (Exception ex)
{
throw;
}
}
// Here method which i want to test with mocked IGroupManager, HubCallerContext and IHubCallerConnectionContext
public partial class RepositoryHub: Hub
{
public override Task OnConnected()
{
try
{
var userProfile = new UserProfile(Context.User);
//NullReference exception Context == null, but why i got it if mocked
//HubCallerContext in test method
Groups.Add(Context.ConnectionId, userProfile.ServerUrl);
// and other useful actions
return base.OnConnected();
}
catch (Exception ex)
{
Log.TraceError(String.Format(" Hub: OnConnected() {0}", ex.Message));
throw;
}
}
}
I figure out easy way as for me. Thanks for attention!
var repository = new RepositoryHub(){ Context = mockHubCallerContext.Object,
Clients = mockClients.Object,
Groups = mockGroupManager.Object };
var r = repository.OnConnected();
For JohnB, answer for your last question:
[TestMethod]
public void Is_OnConnected_Successive()
{
const string connectionId = "1";
dynamic groupName = new ExpandoObject();
var IsSendMessageCalled = false;
groupName.sendMessage = new Action<object>((message) =>
{
IsSendMessageCalled = true;
Debug.WriteLine("sendMessage was called, message: {0}", message);
});
var request = new Mock<IRequest>();
request.Setup(s => s.User.Identity.Name).Returns(user + "&" + server + "&" + password + "&" + level);
request.Setup(s => s.User.Identity.IsAuthenticated).Returns(true);
var mockClients = new Mock<IHubCallerConnectionContext>();
mockClients.Setup(m => m.Group("groupName")).Returns((ExpandoObject)groupName);
var mockGroupManager = new Mock<IGroupManager>();
var mockHubCallerContext = new Mock<HubCallerContext>(request.Object, connectionId);
var hub = new RepositoryHub()
{
Context = mockHubCallerContext.Object,
Clients = mockClients.Object,
Groups = mockGroupManager.Object
};
var testMethod = hub.OnConnected();
Thread.Sleep(threadSleepTime);
//or testMethod.Wait();
Assert.IsTrue(IsSendMessageCalled);
}
Let suggest, here you call your sendMessage(message) method:
public override Task OnConnected()
{
Hub.Clients.Group("groupName").sendMessage("Hello ! for groupName group ");
}
Related
I am trying to mock the two interfaces below.
Mock<IEmailSender> emailSender = new Mock<IEmailSender>();
Mock<IEmailTemplate> emailTemplate = new Mock<IEmailTemplate>();
Here is the setup
emailTemplate.Setup(x => x.GetForgotPasswordTemplate(It.IsAny<EmailTemplateViewModel>())).Returns(It.IsAny<string>());
emailSender.Setup(x => x.SendEmailAsync(It.IsAny<SendEmailViewModel>(), default)).ReturnsAsync(It.IsAny<SendEmailResultViewModel>());
Here is the controller action that is called.
[EnableCors(PolicyName = "AllowClientAccess")]
[HttpGet("Forgot")]
public async Task<IActionResult> ForgotPassword([FromQuery] string email)
{
var user = await _userManager.FindByEmailAsync(email);
if (user != null)
{
//MOQ file path not found
EmailTemplateViewModel model = new EmailTemplateViewModel();
model.Email = email;
model.RecipientName = user.UserName;
var message = _emailTemplate.GetForgotPasswordTemplate(model);
SendEmailViewModel sendEmailViewModel = new SendEmailViewModel();
sendEmailViewModel.RecipientName = user.UserName;
sendEmailViewModel.RecipientEmail = user.Email;
sendEmailViewModel.Subject = "ForgotPassword";
sendEmailViewModel.Body = message;
await _emailSender.SendEmailAsync(sendEmailViewModel);
return Ok(AddSuccess("Check your email", "Forgot Password"));
}
ModelState.AddModelError("Forgot Password","Unable to send email");
return BadRequest(ModelErrors());
}
This line returns null
var message = _emailTemplate.GetForgotPasswordTemplate(model);
Here is the method code
public string GetForgotPasswordTemplate(EmailTemplateViewModel model)
{
try
{
var utcNow = DateTime.Now;
if (_testEmailTemplate == null)
if (File.Exists("Helpers/Templates/ForgotPasswordEmail.template"))
_testEmailTemplate = ReadPhysicalFile("Helpers/Templates/ForgotPasswordEmail.template");
var appUrl = _configuration.GetSection("ApplicationUrl").Value +
"/reset-password?&email=" + model.Email;
var emailMessage = _testEmailTemplate
.Replace("{user}", model.RecipientName)
.Replace("{testDate}", utcNow.ToString(CultureInfo.InvariantCulture))
.Replace("{appUrl}", appUrl);
return emailMessage;
}
catch (Exception e)
{
Log.Warning(e, "Email error");
throw;
}
}
This line also returns null
await _emailSender.SendEmailAsync(sendEmailViewModel);
Here is the method code
public Task<SendEmailResultViewModel> SendEmailAsync(SendEmailViewModel model, SmtpConfig config = default)
{
model.IsHtml = true;
var from = new MailboxAddress(_config.FromName, _config.FromEmail);
var to = new MailboxAddress(model.RecipientName, model.RecipientEmail);
return SendEmailAsync(#from, new[] {to}, model.Body, model.Body, config, model.IsHtml);
}
Here is the test
[Theory]
[InlineData("stephen#kaizenappz.com")]
public async Task WhenAUserForgetsPasswordAHttpStatusCode200ShouldBeReturnedAsync(string email)
{
var confirmUser = await Controller.ForgotPassword(email);
var result = confirmUser as OkObjectResult;
var actual = (HttpStatusCode)result?.StatusCode.Value;
var expected = HttpStatusCode.OK;
Assert.AreEqual(expected, actual);
}
However the test passes and what i am wondering is why do both of these methods return null and why does the test pass even though it returns null. How do i get these to return something?
One thing I do not understand is when to use It.Any and just pass in a normal object with some test data. How am i supposed to check a user exists if i use It.Any and i need to pass a model into my controller action?
Setup phase
Whenever you need to mock an interface method try be permissive during setup.
In other words allow to receive any parameter:
const string mockedForgotPwdTemplate = "...";
emailTemplate
.Setup(template => template.GetForgotPasswordTemplate(It.IsAny<EmailTemplateViewModel>()))
.Returns(mockedForgotPwdTemplate);
If your return value depends on the parameter
then use that overload of the Returns, which accepts a function:
const string mockedTemplateWithSubject = "...";
const string mockedTemplateWithoutSubject = "...";
emailTemplate
.Setup(template => template.GetForgotPasswordTemplate(It.IsAny<EmailTemplateViewModel>()))
.Returns((EmailTemplateViewModel vm) => !string.IsNullOrEmpty(vm.Subject) ? mockedTemplateWithSubject : mockedTemplateWithoutSubject);
Verification phase
During assertion try to be as specific as possible.
If you have access to the parameter then pass that on to the Verify:
var mockedViewTemplate = new EmailTemplateViewModel { ... };
emailTemplate
.Verify(template => template.GetForgotPasswordTemplate(mockedViewTemplate), Times.Once);
Please bear in mind that moq uses reference check to determine that the expected and actual parameter are the same. If you don't have a reference to this parameter then you should use It.Is<T>:
const string expectedSubject = "ForgotPassword";
emailTemplate
.Verify(template => template.GetForgotPasswordTemplate(
It.Is<EmailTemplateViewModel>(vm => expectedSubject == vm.Subject), Times.Once);
or if you wish to assert on more than one attribute then:
private bool AssertViewModel(EmailTemplateViewModel actualVM, string expectedSubject, string expectedRecipientName)
{
Assert.Equal(expectedSubject, actualVM.Subject);
Assert.Equal(expectedRecipientName, actualVM.RecipientName);
return true;
}
//...
const string expectedSubject = "ForgotPassword", expectedRecipent = "...";
emailTemplate
.Verify(template => template.GetForgotPasswordTemplate(
It.Is<EmailTemplateViewModel>(vm => this.AssertViewModel(vm, expectedSubject, expectedRecipient)), Times.Once);
I have this method:
public void Handle(ShipmentConfirmedEvent message)
{
try
{
var trackingOrderDto = new ShipmentConfirmedDto
{
AccountId = message.AccountId,
FirstName = message.CustomerFirstName,
TransactionId = message.TransactionId,
Language = message.LanguageCode,
ExcludedCommunicationChannels = message.ExcludedCommunicationChannels,
TrackingId = message.TrackingNumber
};
Log.Info("Received notify of Shipment Confirmed request with id <{0}> for order {1}", message.GenerationId, message.TransactionId);
if (!string.IsNullOrEmpty(_iosForcePushAccountId))
{
Log.Info("Per device Ios, l'accountId {0} verrĂ forzato a {1} per configurazione", trackingOrderDto.AccountId, _iosForcePushAccountId);
trackingOrderDto.AccountId = Convert.ToInt64(_iosForcePushAccountId);
}
Log.Debug("Send push notification for IOS for AccountId <{0}>", trackingOrderDto.AccountId);
var iosContent = _sender.Create(trackingOrderDto, "IOS");
_sender.IosSend(iosContent);
trackingOrderDto.AccountId = message.AccountId;
if (!string.IsNullOrEmpty(_androidForcePushAccountId))
{
Log.Info("Per device Android, l'accountId {0} verrĂ forzato a {1} per configurazione", trackingOrderDto.AccountId, _androidForcePushAccountId);
trackingOrderDto.AccountId = Convert.ToInt64(_androidForcePushAccountId);
}
Log.Debug("Send push notification for Android for AccountId <{0}>", trackingOrderDto.AccountId);
var androidContent = _sender.Create(trackingOrderDto, "ANDROID");
_sender.AndroidSend(androidContent);
}
catch (ExcludedCommunicationChannelsException ex)
{
Log.Warn(ex.Message);
}
catch (Exception ex)
{
var msg = String.Format("Errore durante la gestione del messaggio relativo al PushNotification for username {0}", message.MailTo.First().Address);
Log.Error(ex, msg);
throw new Exception(ex.Message, ex);
}
Log.Info("<{0}> Processed", message.GenerationId);
}
and I have this test:
[Fact]
public void GivenAnOrderConfirmedEventWithForcedAccountId_WhenHandle_ThenCallSenderWithTheForcedAccountId()
{
NServiceBus.Testing.Test.Initialize();
var service = new ShipmentConfirmedRequestEventConsumer(mockSender, "1111", "2222");
NServiceBus.Testing.Test.Handler(svc => service)
.OnMessage<ShipmentConfirmedEvent>(
m =>
{
m.AccountId = 407716;
m.CustomerFirstName = "Marco";
m.TransactionId = "T123456";
m.LanguageCode = "IT";
m.TrackingNumber = "642167921";
}
);
mockSender.AssertWasCalled(x => x.Create(Arg<ShipmentConfirmedDto>.Matches(dto => dto.AccountId == 2222), Arg<string>.Is.Equal("ANDROID")));
mockSender.AssertWasCalled(x => x.Create(Arg<ShipmentConfirmedDto>.Matches(dto => dto.AccountId == 1111), Arg<string>.Is.Equal("IOS")));
}
the second AssertWasCalled, the one related to IOS, throw exception because it seems to be overwritten, being within the method the first to be called.
I need to verify that the Create method is called twice within the method, with the parameters specified.
How can I modify the test in order to verify it?
The solution is to modify test this way:
[Fact]
public void GivenAnOrderConfirmedEventWithForcedAccountId_WhenHandle_ThenCallSenderWithTheForcedAccountId()
{
NServiceBus.Testing.Test.Initialize();
mockSender.Expect(x => x.Create(Arg<ShipmentConfirmedDto>.Matches(dto => dto.AccountId == 2222), Arg<string>.Is.Equal("ANDROID"))).Return(string.Empty);
mockSender.Expect(x => x.Create(Arg<ShipmentConfirmedDto>.Matches(dto => dto.AccountId == 1111), Arg<string>.Is.Equal("IOS"))).Return(string.Empty);
var service = new ShipmentConfirmedRequestEventConsumer(mockSender, "1111", "2222");
NServiceBus.Testing.Test.Handler(svc => service)
.OnMessage<ShipmentConfirmedEvent>(
m =>
{
m.AccountId = 407716;
m.CustomerFirstName = "Marco";
m.TransactionId = "T123456";
m.LanguageCode = "IT";
m.TrackingNumber = "642167921";
}
);
mockSender.VerifyAllExpectations();
}
I have the following code.
[HttpGet]
public async Task<List<TenantManagementWebApi.Entities.SiteCollection>> Get()
{
var tenant = await TenantHelper.GetActiveTenant();
var siteCollectionStore = CosmosStoreFactory.CreateForEntity<TenantManagementWebApi.Entities.SiteCollection>();
await siteCollectionStore.RemoveAsync(x => x.Title != string.Empty); // Removes all the entities that match the criteria
string domainUrl = tenant.TestSiteCollectionUrl;
string tenantName = domainUrl.Split('.')[0];
string tenantAdminUrl = tenantName + "-admin.sharepoint.com";
KeyVaultHelper keyVaultHelper = new KeyVaultHelper();
await keyVaultHelper.OnGetAsync(tenant.SecretIdentifier);
using (var context = new OfficeDevPnP.Core.AuthenticationManager().GetSharePointOnlineAuthenticatedContextTenant(tenantAdminUrl, tenant.Email, keyVaultHelper.SecretValue))
{
Tenant tenantOnline = new Tenant(context);
SPOSitePropertiesEnumerable siteProps = tenantOnline.GetSitePropertiesFromSharePoint("0", true);
context.Load(siteProps);
context.ExecuteQuery();
List<TenantManagementWebApi.Entities.SiteCollection> sites = new List<TenantManagementWebApi.Entities.SiteCollection>();
foreach (var site in siteProps)
{
if(site.Template.Contains("SITEPAGEPUBLISHING#0") || site.Template.Contains("GROUP#0"))
{
string strTemplate= default(string);
if(site.Template.Contains("SITEPAGEPUBLISHING#0"))
{
strTemplate = "CommunicationSite";
};
if (site.Template.Contains("GROUP#0"))
{
strTemplate = "Modern Team Site";
};
try
{
Guid id = Guid.NewGuid();
Entities.SiteCollection sc = new Entities.SiteCollection()
{
Id = id.ToString(),
Owner = site.Owner,
Template = strTemplate,
Title = site.Title,
Active = false,
Url = site.Url
};
var added = await siteCollectionStore.AddAsync(sc);
sites.Add(sc);
}
catch (System.Exception ex)
{
throw ex;
}
}
}
return sites;
};
}
However the following lines, I am repeating them on every method:
var tenant = await TenantHelper.GetActiveTenant();
var siteCollectionStore = CosmosStoreFactory.CreateForEntity<TenantManagementWebApi.Entities.SiteCollection>();
await siteCollectionStore.RemoveAsync(x => x.Title != string.Empty); // Removes all the entities that match the criteria
string domainUrl = tenant.TestSiteCollectionUrl;
string tenantName = domainUrl.Split('.')[0];
string tenantAdminUrl = tenantName + "-admin.sharepoint.com";
KeyVaultHelper keyVaultHelper = new KeyVaultHelper();
await keyVaultHelper.OnGetAsync(tenant.SecretIdentifier);
I will have lots of API controllers on my project
Is there an easy way (not refactor as a method), to make my code cleaner and inject the variables I need without copying and pasting every single time?
Hi I`m trying to unit test method with asynchronous web service call (asmx) . Code is as below. Problem is with mocking somehow, TaskCompletionSource .Should I use this pattern ?? Is there any way make it testable.
public async Task<Result> CreateConfAsync(byte[] sesja, Conference conference)
{
Result rez = new Result(-1,"error");
try
{
var confsStrXml = ConferenceHelper.createConfsXmlString(conference);
var tcs = new TaskCompletionSource<WsWynik>();
_proxy.KonferencjaZapiszCompleted += GetCreateConfAsyncCallBack;
_proxy.KonferencjaZapiszAsync(sesja, confsStrXml,tcs);
var wsWynik = await tcs.Task;
rez.status = wsWynik.status;
rez.message = wsWynik.status_opis;
if (rez.status != 0) SesjaExceptionCheck.SesjaCheckThrowIfError(rez.status, rez.message);
}
catch (Exception ex)
{
throw ex;
}
finally
{
_proxy.KonferencjaZapiszCompleted -= GetCreateConfAsyncCallBack;
}
return rez;
}
public void GetCreateConfAsyncCallBack(object sender, KonferencjaZapiszCompletedEventArgs e)
{
var tcs = (TaskCompletionSource<WsWynik>)e.UserState;
if (e.Cancelled)
{
tcs.TrySetCanceled();
}
else if (e.Error != null)
{
tcs.TrySetException(e.Error);
}
else
{
tcs.TrySetResult(e.Result);
}
}
I`ve try to mock TaskCompletionSource, but no result .
[TestMethod]
public async Task CreateConf_ShouldBeOk()
{
var conf = new Mock<Conference>();
var tcs = new TaskCompletionSource<WsWynik>();
tcs.SetResult(default(WsWynik));
_proxy.Setup(x => x.KonferencjaZapiszAsync(_sesja, It.IsAny<string>(),tcs))
.Raises(mock => mock.KoszykKonferencjaZapiszCompleted += null, new EventArgs());
ConferenceRepository confRep = new ConferenceRepository(_proxy.Object, _dictRep.Object);
var res = await confRep.CreateConfAsync(_sesja, conf.Object);
Assert.IsTrue(1 == 1);
}
A few things need to be addressed.
The task completion source cannot be mocked as it is created within the method under test. It is not needed to mock anyway.
Use argument matchers for the mocked proxy method so that is will invoke when passed the values from the method.
For the event being raised, the proper event argument needs to be passed with the mock in order for the system under test to behave as desired.
[TestMethod]
public async Task CreateConf_ShouldBeOk() {
//Arrange
var conf = new Mock<Conference>();
var eventArgs = new KonferencjaZapiszCompletedEventArgs(...) {
Result = //...,
//populate the necessary properties
};
_proxy
.Setup(_ => _.KonferencjaZapiszAsync(
It.IsAny<byte[]>(),
It.IsAny<string>(),
It.IsAny<TaskCompletionSource<WsWynik>>()
))
.Raises(_ => _.KoszykKonferencjaZapiszCompleted += null, eventArgs);
var repository = new ConferenceRepository(_proxy.Object, _dictRep.Object);
//Act
var result = await repository.CreateConfAsync(_sesja, conf.Object);
//Assert
Assert.IsNotNull(result);
Assert.AreEqual(result.status, expectedStatus);
Assert.AreEqual(result.message , expectedMessage);
//assert the expected values of the result members
}
I am new to Web api and json. I am unaware of calling method which are in WebApi. Below method is in Webapi:
[HttpGet]
public bool AddAccount([FromRoute]string accountname)
{
try
{
BizFramework.Web.Model.Account data = new BizFramework.Web.Model.Account();
data.AccountGuid = Guid.NewGuid();
data.AccountName = accountname;
data.ParentAccountID = 0;
data.AccountTypeID = 13;
data.AccountNo = "8060";
data.Active = true;
data.HierarchyLevel = 1;
data.CashFlowID = 3;
data.OpeningBalanceDate = DateTime.Now;
data.IscashBasis = true;
data.Createdby = "BAOwner";
data.CreatedDatetime = DateTime.Now;
data.Modifiedby = "BAOwner";
data.ModifiedDatetime = DateTime.Now;
BA.AddToAccounts(data);
BA.SaveChanges();
return true;
}
catch (Exception ex)
{
File.AppendAllText(AppDomain.CurrentDomain.BaseDirectory + "log.txt", ex.ToString());
return false;
}
}
Using this link :
http://example.com/CustomerPortalService12/AddAccount/AccountsReceivable
I am able to add. But through the coding how can I add?
public void AddAccount(string accountname, Action<bool> success, Action<bool> failure)
{ var client = new RestClient("http://[localhost]/CustomerPortalService12");
// client.Authenticator = new HttpBasicAuthenticator(username, password);
var request = new RestRequest("AddAccount/AccountsReceivable/" + accountname, Method.GET);
client.ExecuteAsync(request, (response) =>
{
if (response.ResponseStatus == ResponseStatus.Error)
{
failure(response.ErrorMessage);
}
else
{
var result= JsonConvert.DeserializeObject<bool>(response.Content);
success(result);
}
}); }
to call this function
AddAccount("accountname",
(item) => Dispatcher.BeginInvoke(() =>
{
MessageBox.Show("Done!");
}),
(error) => Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(error);
}));
I have done this by using RestSharp.
For more details go to here
http://restsharp.org/