This is the code of my controller :
private readonly ILMS_Service lms_client;
private UrlHelper urlHelper;
public PackagesController(ILMS_Service client, UrlHelper _urlHelper)
{
lms_client = client;
urlHelper = _urlHelper;
}
public PackagesController()
{
lms_client = new LMS_ServiceClient();
urlHelper = new UrlHelper(Request.RequestContext);
}
[HttpPost]
public ActionResult EditPackageDetails(
int packageID,
string package_name,
int unit_type,
int product_id,
int unit_count,
string description
)
{
lms_client.EditPackageDetails(
packageID,
package_name,
unit_type,
product_id,
unit_count,
description);
var url = urlHelper.Action("PackagesList", "Packages");
return Json(new
{
statusCode = (int)HttpStatusCode.OK,
redirectURL = url
});
}
The urlBuilder.Action("PackagesList", "Packages");
returns null during the test run. I am trying to fake the UrlHelper
class with a fake return value by assigning it to the controller but it doesn't seem to work. Here is the current implementation of my test:
private readonly PackagesController _controller_Packages;
private readonly ILMS_Service _lms_service;
private readonly HttpContextBase httpContext;
private readonly HttpResponseBase httpResponse;
private readonly HttpSessionStateBase httpSession;
private readonly UrlHelper urlBuilder;
public Packages_UnitTest()
{
// Mock WCF
_lms_service = A.Fake<ILMS_Service>();
// Fake session
httpContext = A.Fake<HttpContextBase>();
httpResponse = A.Fake<HttpResponseBase>();
httpSession = A.Fake<HttpSessionStateBase>();
urlBuilder = A.Fake<UrlHelper>();
//SUTs
_controller_Packages = new PackagesController(_lms_service, urlHelper);
A.CallTo(() => httpContext.Response).Returns(httpResponse);
A.CallTo(() => httpContext.Session).Returns(httpSession);
}
[TestMethod]
public void should_EditPackageDetails()
{
// Arrange
int packageID = 1;
string package_name = "Test package";
int unit_type = 1;
int product_id = 1;
int unit_count = 10;
string description = "Sample test description";
int expected_statusCode = (int)HttpStatusCode.OK;
string expected_page_destination = "/Packages/PackagesList";
var context = new ControllerContext(new RequestContext(httpContext, new RouteData()), _controller_Packages);
_controller_Packages.ControllerContext = context;
A.CallTo(() => urlBuilder.Action("PackagesList", "Packages"))
.Returns("/Packages/PackagesList");
// Act
_ = A.CallTo(() => _lms_service.EditPackageDetails(
A<int>.Ignored,
A<string>.Ignored,
A<int>.Ignored,
A<int>.Ignored,
A<int>.Ignored,
A<string>.Ignored
));
var _editPackage = _controller_Packages.EditPackageDetails(
packageID,
package_name,
unit_type,
product_id,
unit_count,
description
) as JsonResult;
dynamic result = _editPackage.Data;
// Assert
Assert.AreEqual(expected_statusCode, result.statusCode);
Assert.AreEqual(expected_page_destination, result.redirectURL);
}
With this test, it is still returning null, not "/Packages/PackagesList"
. How can I fake UrlHelper
with it returning "/Packages/PackagesList"
as the value with FakeitEasy? Any help would be appreciated. I have an ASP.NET MVC 4, MSTest, and FakeitEasy mocking framework. Thanks!
CodePudding user response:
The fake UrlHelper
looks fine to me, but you're not using it inside EditPackageDetails
. You're using a new UrlHelper
that you construct:
var urlBuilder = new UrlHelper(Request.RequestContext);
use _controller_Packages.Url
instead.
And a hint for the future: it can often be helpful to debug your tests. Examine the values that you're using that you think might be Fakes, to see if they really are.
CodePudding user response:
I ended up injecting the UrlHelper to the constructor of the SUT and added an if
statement to check if the urlBuilder
has been already instantiated. Once the .Action()
is called, it will then return the faked path I defined as you can see on the A.CallTo()
part of my test.
Note that the SUT and test below is just an excerpt of my full code to clear out distractions.
SUT
private UrlHelper urlHelper;
public PackagesController(UrlHelper _urlHelper)
{
urlHelper = _urlHelper;
}
[HttpPost]
public ActionResult EditPackageDetails(
int packageID,
string package_name,
int unit_type,
int product_id,
int unit_count,
string description
)
{
lms_client.EditPackageDetails(
packageID,
package_name,
unit_type,
product_id,
unit_count,
description);
if(urlHelper == null)
urlHelper = new UrlHelper(Request.RequestContext);
var url = urlHelper.Action("PackagesList", "Packages");
return Json(new
{
statusCode = (int)HttpStatusCode.OK,
redirectURL = url
});
}
Test
private readonly PackagesController _controller_Packages;
private readonly ILMS_Service _lms_service;
private readonly UrlHelper urlHelper;
public Packages_UnitTest()
{
// Mock WCF
_lms_service = A.Fake<ILMS_Service>();
// Fakes
urlHelper = A.Fake<UrlHelper>();
// SUTs
_controller_Packages = new PackagesController(_lms_service, urlHelper);
}
[TestMethod]
public void should_EditPackageDetails()
{
// Arrange
int packageID = 1;
string package_name = "Test package";
int unit_type = 1;
int product_id = 1;
int unit_count = 10;
string description = "Sample test description";
int expected_statusCode = (int)HttpStatusCode.OK;
string expected_page_destination = "/Packages/PackagesList";
var context = new ControllerContext(new RequestContext(httpContext, new RouteData()), _controller_Packages);
_controller_Packages.ControllerContext = context;
A.CallTo(() => urlHelper.Action("PackagesList", "Packages"))
.Returns("/Packages/PackagesList");
// Act
_ = A.CallTo(() => _lms_service.EditPackageDetails(
A<int>.Ignored,
A<string>.Ignored,
A<int>.Ignored,
A<int>.Ignored,
A<int>.Ignored,
A<string>.Ignored
));
var _editPackage = _controller_Packages.EditPackageDetails(
packageID,
package_name,
unit_type,
product_id,
unit_count,
description
) as JsonResult;
dynamic result = _editPackage.Data;
// Assert
Assert.AreEqual(expected_statusCode, result.statusCode);
Assert.AreEqual(expected_page_destination, result.redirectURL);
}
The if
statement on my method seems to be a hacky way to fake UrlHelper. It wasn't my intention to add the conditional statement there though so this is not the most elegant way of doing this. If there's a better implementation, please let me know. Any additional information always helps!