I am still learning to use MSTest and Moq for automated unit testing in my application. I have successfully mocked the code and run it. It is showing that the tests are passed , but the code coverage is 0%. This is my code below.What needs to be changed so that code coverage becomes 100%.
I know this question has been asked a couple of times before, but nothing seems to help me.So can anyone suggest me what am I doing wrong.
Any help is highly appreciated.Thanks.
PS: I'm using Sonarcube for knowing the code coverage.
using Moq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Threading.Tasks;
using System.Diagnostics.CodeAnalysis;
namespace MyNameSpace
{
[TestClass]
public class ApplicationTest
{
readonly Helper moqHelper = new Helper();
[TestMethod()]
public void GetDataFromDataBaseMoq()
{
Task<bool> returnValue;
Mock<Application> mockType = new Mock<Application>();
mockType.CallBase = true;
mockType.Setup(x => x.GetDataFromDataBase()).Returns(returnValue = moqHelper.GetDataFromDataBaseMoq());
if (returnValue.Result)
{
Assert.IsTrue(true);
}
else
{
Assert.Fail();
}
}
}
[ExcludeFromCodeCoverage]
class Helper
{
internal async Task<bool> GetDataFromDataBaseMoq()
{
bool returnValue = true;
return returnValue;
}
}
public class Application : IApplication
{
public virtual async Task<bool> GetDataFromDataBase()
{
//if data retrive successfull, return true, else false
return true;
}
}
public interface IApplication
{
Task<bool> GetDataFromDataBase();
}
}
You're not testing your application code, you're testing your mock. You could've seen this by setting a breakpoint in Application.GetDataFromDataBase() and debugging your test; you'd see it won't be hit.
You need to only mock dependencies, if any. So rewrite your test to actually call into your code:
[TestMethod]
public async Task GetDataFromDataBase_Returns_True()
{
// Arrange
IApplication classUnderTest = new Application();
// Act
var result = await classUnderTest.GetDataFromDataBase();
// Assert
Assert.IsTrue(result);
}
And you'll see the need for all the mocks and helpers goes away.
Related
I am new to unit testing,
I am working on a minimal API project. and I am testing an endpoint with xunit, moq
endpoint class - ParticipantsGetAll.cs
public class ParticipantsGetAll : IEndpoint<IResult, GetAllParticipantsRequest>
{
const string uri = "api/participants-all";
private ParticipantService? participantService;
public void AddRoute(IEndpointRouteBuilder app)
{
app.MapPost(uri, async ( ParticipantService participantService, [FromBody] GetAllParticipantsRequest query) =>
{
this.participantService = participantService;
return await HandleAsync(query);
})
.Produces<List<ParticipantSummaryModel>>()
.WithTags("Participants")
.WithName("GetAllParticipants");
}
public async Task<IResult> HandleAsync( GetAllParticipantsRequest query)
{
var participants = await participantService!.ListAllAsync(query);
return Results.Ok(participants);
}
I tried to write a unit test test above endpoint class.
CreateParticipantApiTest.cs
[Fact]
public async void ListAllAsyncShouldReturn200Status()
{
var query = new GetAllParticipantsRequest()
{
Name= "",
KeyCordinator="",
RelatedConnection="",
Statuses = null
};
var participant = ParticipantMockData.NewParticipantModel(); // a static class
var sut = new ParticipantsGetAll();
var result = (OkObjectResult)await sut.HandleAsync(query);
result.StatusCode.Should().Be(200);
}
I got below error
Message:
System.NullReferenceException : Object reference not set to an instance of an object.
Stack Trace:
ParticipantsGetAll.HandleAsync(GetAllParticipantsRequest query) line 36
CreateParticipantApiTest.ListAllAsyncShouldReturn200Status() line 67
I have no idea why the object tis null.
Please anyone help me to find the problem.
I am facing this issue for a long time
Thanks
I have no idea why the object tis null.
That is pretty clear, because in your unit test you invoke HandleAsync directly, so the setup which you have moved into MapPost does not happen (compiler was trying to help but was shut down with null-forgiving operator in participantService!.ListAllAsync(query)). Also I'm pretty sure this way of using handlers can lead to some concurrency problems (if ParticipantService is a scoped service). Move ParticipantService participantService to HandleAsync. Something along this lines (not tested):
public class ParticipantsGetAll : IEndpoint<IResult, GetAllParticipantsRequest>
{
const string uri = "api/participants-all";
public void AddRoute(IEndpointRouteBuilder app)
{
app.MapPost(uri, HandleAsync)
.Produces<List<ParticipantSummaryModel>>()
.WithTags("Participants")
.WithName("GetAllParticipants");
}
public async Task<IResult> HandleAsync(ParticipantService participantService, [FromBody] GetAllParticipantsRequest query)
{
var participants = await participantService.ListAllAsync(query);
return Results.Ok(participants);
}
}
And modify the test accrodingly.
I am currently writing unit tests for a TagHelper that uses IActionDescriptorCollectionProvider in its constructor. My setupt looks as below so far - any ideas on how to set up something to satisfy IActionDescriptorCollectionProvider and allow me to change the value of IActionDescriptorCollectionProvider.ActionDescriptors.Items for my testing?
I can't use the DefaultActionDescriptorCollectionProvider implementation as it is inaccessible. Is there a simple way of doing this, or should I just substitute it with NSubstitute?
[SetUp]
public void Setup()
{
IHttpContextAccessor contextAccessor = new HttpContextAccessor();
contextAccessor.HttpContext = new DefaultHttpContext();
contextAccessor.HttpContext.Request.Path = "/foo";
IActionDescriptorCollectionProvider actionDescriptorCollectionProvider;
actionDescriptorCollectionProvider = new DefaultActionDescriptorCollectionProvider();
ActivePathSegmentTagHelper helper;
helper = new ActivePathSegmentTagHelper(contextAccessor, actionDescriptorCollectionProvider);
helper.Area = "";
helper.Controller = "Home";
helper.Action = "Index";
}
As far as I know, if you want to use IActionDescriptorCollectionProvider in unit test, you could directly mock it and then use delegate with it.
More details, you could refer to below test demo source codes:
https://github.com/dotnet/aspnetcore/blob/c565386a3ed135560bc2e9017aa54a950b4e35dd/src/Mvc/Mvc.Core/test/Routing/ActionEndpointDataSourceBaseTest.cs
Its too late for u.. but for someone else heading this problem.. I just used this class
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Moq;
using System.Collections.Generic;
public abstract class ActionDescriptorCollectionProviderMock
{
public static readonly IActionDescriptorCollectionProvider ADCP = GetADCP();
private static IActionDescriptorCollectionProvider GetADCP()
{
var actionDescriptorCollectionProviderMock = new Mock<IActionDescriptorCollectionProvider>();
actionDescriptorCollectionProviderMock.Setup(m => m.ActionDescriptors).Returns(new ActionDescriptorCollection(new List<ActionDescriptor>(), 0));
return actionDescriptorCollectionProviderMock.Object;
}
}
and in test:
[Fact]
public async void GetByIdTest()
{
//Arrange
var controller = new SomeController(ActionDescriptorCollectionProviderMock.ADCP);
//Act
...
//Assert
...
}
When I implement cross browser testing with nunit using TestFixture my tests fails when run together, passed when run individually. Exception was throwed when SendKeys method was called because argument was null, but this is not the cause, because when i run this test again test will passed. Ofcourse im tried to debug this issue but i dont find solution. Simple OpenHomePage Test works fine. Here is my code:
[TestFixture(typeof(ChromeDriver))]
[TestFixture(typeof(FirefoxDriver))]
public class TestClass<TWebDriver> where TWebDriver : IWebDriver, new()
{
[OneTimeSetUp]
public void CreateDriver()
{
try
{
PropertiesCollection.driver = new TWebDriver();
Console.WriteLine("Opened browser");
PropertiesCollection.driver.Url = "http://localhost:81/";
Console.WriteLine("Opened URL");
PropertiesCollection.driver.Manage().Window.Maximize();
//initialize test data from excel sheet
ExcelLib.PopulateInCollection(#"c:\users\bolec\documents\visual studio 2015\Projects\RowingSectionTests\RowingSectionTests\TestData.xlsx");
}
catch (Exception msg)
{
Console.WriteLine(msg.ToString());
}
}
[OneTimeTearDown]
public void FixtureTearDown()
{
HomePageObjects homeObj = new HomePageObjects();
homeObj.Logoff();
if (PropertiesCollection.driver != null) PropertiesCollection.driver.Quit();
}
[TearDown]
public void TearDown()
{
//Take screen on failure
if (TestContext.CurrentContext.Result.Outcome.Status.Equals(TestStatus.Failed))
{
string fileName = Regex.Replace(TestContext.CurrentContext.Test.FullName + "_" + DateTime.Now.ToString(), "[^a-z0-9\\-_]+", "_", RegexOptions.IgnoreCase);
((ITakesScreenshot)PropertiesCollection.driver).GetScreenshot().SaveAsFile(#"c:\users\bolec\documents\visual studio 2015\Projects\RowingSectionTests\RowingSectionTests\Screenshots\" + fileName + ".png", System.Drawing.Imaging.ImageFormat.Png);
}
}
//will always passed
[Test]
public void OpenHomePage()
{
HomePageObjects homeObj = new HomePageObjects();
}
//login with correct credentials will login to acc
[Test]
public void Login()
{
HomePageObjects homeObj = new HomePageObjects();
LoginPageObjects loginObj = homeObj.ToLoginPage();
loginObj.Login(ExcelLib.ReadData(1, "UserName"), ExcelLib.ReadData(1, "Password"));
//checking is URL correct after loggin
Assert.AreEqual("http://localhost:81/", PropertiesCollection.driver.Url.ToString());
//checking is login is correct on navbar
Assert.AreEqual(homeObj.GetUserLoginStringInButton().ToLower(), ExcelLib.ReadData(1, "UserName").ToLower());
}
The problem with using the static PropertiesCollection is that any changes to the static class in one test will be reflected in the other test, making the chances or creating a test dependency very high (as you have discovered).
You have two choices, firstly don't use a static instead create an instance. Alternatively, ensure that in a setup and your teardown methods you set/reset your PropertiesCollection back to it's required state.
Using the OneTimeSetUp attribute is also risky as it only runs once for all the tests in your fixture.
I'm setting up regression testing for my ASP.NET 5 project using beta8. When I setup the test fixtures I want to fire up kestrel so that I could run selenium tests against it without the need for any external web server. How do I do this?
It's basically something like this:
public class RegressionTests : IDisposable
{
public RegressionTests()
{
// Start kestrel
}
[Fact]
public void Test1()
{
Assert.True(true);
// more tests...
}
public void Dispose()
{
// Shutdown kestrel
}
}
This is what I've tried so far but I couldn't get it to work. It doesn't pick up the project.json file. Well, to be honest, I don't know what to pass to it since I can't find anywhere what command args I can pass to Microsoft.AspNet.Hosting.Program.
new Microsoft.AspNet.Hosting.Program(CallContextServiceLocator.Locator.ServiceProvider).Main(
new[]
{
"--server",
"Microsoft.AspNet.Server.Kestrel",
"--project",
"../Web/project.json",
"--port",
"5001",
});
Thanks #Victor Hurdugaci. For the google folks of the future, this is what I ended up having. This is a test fixture that I use for xunit. The TestConfiguration class is missing but you should get the idea. You need to add a dependency on Microsoft.AspNet.Server.Testing.
public class WebTestsFixture : IDisposable
{
private readonly IApplicationDeployer _deployer;
private readonly IDisposable _loggerScope;
public WebTestsFixture()
{
var logger = new LoggerFactory()
.AddConsole(LogLevel.Information)
.CreateLogger("Regression");
_loggerScope = logger.BeginScope("RegressionTestSuite");
var deploymentParameters = new DeploymentParameters(
TestConfiguration.Configuration.Get<string>("Settings:ApplicationPath"),
(ServerType)Enum.Parse(typeof(ServerType), TestConfiguration.Configuration.Get<string>("Settings:ServerType")),
RuntimeFlavor.Clr,
RuntimeArchitecture.x86)
{
ApplicationBaseUriHint = TestConfiguration.Configuration.Get<string>("Settings:ApplicationUri"),
EnvironmentName = TestConfiguration.Configuration.Get<string>("Settings:EnvironmentName"),
PublishWithNoSource = false
};
_deployer = ApplicationDeployerFactory.Create(deploymentParameters, logger);
DeploymentResult = _deployer.Deploy();
}
public DeploymentResult DeploymentResult { get; private set; }
public void Dispose()
{
_loggerScope.Dispose();
_deployer.Dispose();
}
}
#mardoxx points out that a more modern and much simpler approach to testing is documented here.
How can I verify that a method was called on a mock when the method itself is called in a delegate passed to Task.Run? By time mock.Verify is called the Task still hasn't executed.
I have tried await Task.Delay just before mock.Verify but this seems to leave the test runner hanging.
The reason for using Task.Run is to offload the logic to prevent an attacker from being able to differentiate whether the email address exists in the system by the time to execute.
using System.Threading.Tasks;
using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace AsyncTesting
{
class MyController : Controller
{
public IEmailService EmailService { get; set; }
public MyController(IEmailService emailService)
{
EmailService = emailService;
}
public ViewResult BeginPasswordReset(string emailAddress)
{
BeginPasswordResetAsync(emailAddress);
return View();
}
private Task BeginPasswordResetAsync(string emailAddress)
{
return Task.Run(delegate
{
EmailService.Send(emailAddress);
});
}
}
internal interface IEmailService
{
void Send(string emailAddress);
}
internal class MyControllerTests
{
[TestMethod]
public void BeginPasswordReset_SendsEmail()
{
var mockEmailService = new Mock<IEmailService>();
var controller = new MyController(mockEmailService.Object);
const string emailAddress = "email#domain.com";
controller.BeginPasswordReset(emailAddress);
mockEmailService.Verify(es=>es.Send(emailAddress));
}
}
}
In your task you could set a ManualResetEvent (which our test code blocks on using something like:
Assert.IsTrue(yourEvent.WaitForOne(TimeSpan.FromSecond(<max time you want to wait>), "the event failed to run");
like this:
public void BeginPasswordReset_SendsEmail()
{
const string emailAddress = "email#domain.com";
ManualResetEvent sendCalled= new ManualResetEvent(false);
var mockEmailService = new Mock<IEmailService>();
mockEmailService.Setup(m => m.Send(emailAddress)).Callback(() =>
{
sendCalled.Set();
});
var controller = new MyController(mockEmailService.Object);
controller.BeginPasswordReset(emailAddress);
Assert.IsTrue(sendCalled.WaitOne(TimeSpan.FromSeconds(3)), "Send was never called");
mockEmailService.Verify(es => es.Send(emailAddress));
}
Some quick research it looks like it is possible with MSTest. e.g.
[TestMethod]
public async Task BeginPasswordResetAsync();
{
await BeginPasswordResetAsync("emailAddress");
mockEmailService.Verify...
}