I am unit testing my API calls, the problem is every time we do an API call, .Net creates another HttpContext.Current.Session instance. So for short, we can't use session variables.
Any thoughts on how this will be handled.
I'm hoping for something that does not alter the existing codes, just the unit test codes.
Unit Test Code
var car = getByUrl("getCarBySessionId");
var train = getByUrl("getTrainBySessionId");
These are the API
[Route("api/getCarBySessionId")]
public Car GetCarBySessionId(int id)
{
var sessionId = HttpContext.Current.Session[SessionId];
_service.GetCarBySessionId(sessionId);
}
[Route("api/getTrainBySessionId")]
public Train GetTrainBySessionId(int id)
{
var sessionId = HttpContext.Current.Session[SessionId];
_service.GetTrainBySessionId(sessionId);
}
What happens here is that the 2 sessionIds are not the same. I was expecting it to have the same values but it generates 2 different sessionIds.
Related
I'm quite new to testing.
I've got a really simple method that creates a Stripe user and attaches their Id to their User object in DB.
[Fact(DisplayName = "AddStripeCustomerIdAsync should save a StripeId to the User")]
public async Task Test_AddStripeCustomerIdAsync()
{
// Arrange
var customerCreateOptions = new CustomerCreateOptions
{
Email = "test#test.com"
};
// Act
await _userCustomerService.AddStripeCustomerIdAsync(user, customerCreateOptions);
// Assert
Assert.False(user.StripeCustomerId.IsNullOrEmpty());
}
it works great. However a lot of other Stripe related tests rely on there being a valid Stripe Customer Id in the StripeCustomerId field. For example,
[Fact(DisplayName = "AddCardToAccount should add a reference for a card to the user.")]
public async Task Test_AddCardToAccount()
{
// Act
var result = paymentService.AddCardPaymentMethod(
user,
"4242424242424242",
9,
2025,
"552");
// Assert
Assert.True(result);
}
This test fails, unless I hard code in a real Stripe customer Id to the user, or call the function that attaches a Stripe Id before running every test that uses it.
So currently I have
user = new ApplicationUser
{
StripeCustomerId = "cus_ ..."
};
Which just feels WRONG. If that value is not a real Stripe customerId, Stripe exceptions are thrown everywhere. Am I doing okay and this is something that can't be helped, or am I missing something?
Solved it by creating a new Stripe customer with every test that needs a CustomerId. Just hope I don't get rate limited lol
EDIT
I was a foolish young developer at this time. My solution was to change my interface so that it doesn't return a Stripe object. I made a customer object that made mocking my Service using Stripe a lot easier.
I'm applying NUnit integration tests on our controller endpoints in a .NET Web API 2 project whose models and controllers are generated via Entity code first from database.
I'm having trouble thinking of what parts of the controller I should test. In the end, we'd just like to be able to automate "can a user with "x" role get this data?"
Looking in the GET portion of this controller, what parts would you test and what's your reasoning?
namespace api.Controllers.myNamespace
{
public class myController : ApiController
{
private string strUserName;
private string strError = "";
private string strApiName = "myTable";
private myDatabase db = new myDatabase();
// ----------------------------------------------------------------------
// GET: api/path
public IQueryable<myTable> GetmyTable()
{
try
{
this.strUserName = this.getUserName();
if
(
// ----- authorize -----
db.view_jnc_role_api_permission.Count
(
view =>
(
view.permission == "get"
&& view.apiName == this.strApiName
&& view.userName == this.strUserName
)
) == 1
// ----- /authorize -----
)
{
// ----- get -----
IQueryable<myTable> data =
from tbl in db.myTable
where tbl.deleted == null
select tbl;
// ----- /get -----
return data;
}
else
{
strError = "Unauthorized.";
throw new HttpResponseException(HttpStatusCode.Forbidden);
}
}
catch (Exception ex)
{
if (strError.Length == 0)
{
if (this.showException())
{
strError = ex.ToString();
}
}
throw new HttpResponseException(ControllerContext.Request.CreateErrorResponse(HttpStatusCode.Forbidden, strError));
}
}
}
For reference, here's what I have so far. Some of these private fields I'm defining shouldn't be here - currently trying to get access to private methods from my test project via AssemblyInfo.cs to fix this:
namespace api.myNamespace
{
[TestFixture]
public class myController : ApiController
{
private string strUserName;
private string strError = "";
private string strApiName = "myTable";
private myDb db = new myDb();
// Using TransactionScope to (hopefully) prevent integration test's changes to database from persisting
protected TransactionScope TransactionScope;
// Instantiate _controller field
private myController _controller;
[SetUp]
public void SetUp() {
TransactionScope = new TransactionScope(TransactionScopeOption.RequiresNew);
// It's possible that one test may leave some state which could impact subsequent tests - so we must reinstantiate _controller at the start of each new test:
_controller = new myController();
}
[TearDown]
public void TearDown()
{
TransactionScope.Dispose();
}
**//------ TESTS -------//
// CanSetAndGetUserName
// AuthorizedUserCanGetData
// UnauthorizedUserCannotGetData
// AuthorizedUserCanPutData
// UnauthorizedUserCannotPutData
// AuthorizedUserCanPostData
// UnauthorizedUserCannotPostData
// AuthorizedUserCanDeleteData
// UnauthorizedUserCannotDeleteData**
[Test]
public void CanGetAndSetUsername()
{
// ARRANGE
var user = _controller.getUserName();
// ACT
// ASSERT
Assert.That(user, Is.EqualTo("my-internal-username"));
}
[Test]
public void UnauthorizedUserCannotGetData()
{
var user = "Mr Unauthorized";
// Unfinished bc integration testing is super abstract, subjective, hard, time consuming and hard. All downvoters are plebs.
Assert.That(user, Is.EqualTo());
}
}
}
}
integration tests means several things:
you setup your test data in the database, via a script for example.
you call the endpoint under test knowing exactly what data you should call it with and what you should get. This is all based on your test data you setup in step 1.
you compare your expected data with the one you got back.
this is an integration test as it touches everything, both api and database.
Now, you said you are having trouble deciding which parts of the controller to test. This suggests you are confusing integration tests with unit tests.
Integration tests we already covered.
Unit tests cover parts of functionality. You do not test controllers, forget about that.
What you really need to consider doing is this:
First, separate your code from the controller. Keep the controller very basic. It receives a call, validates the request model and passes it further to a class library where the functionality happens. This allows you to forget "testing the controller" and focus on your functionality instead. Unit tests will help here and your test cases will become something like this
I have a user, set up in a certain way.
I have some data, set up in a certain way
When I call method X, then I should get this response.
With such a setup in place, you can set your test data any way you like and check every single test case.
The only reason you wonder how you test your controller is because you dumped all your code into it, which of course makes everything hard. Think SOLID, think SOC ( Separation of concerns ).
One piece of advice: never ever return IQueryable from an endpoint, that's not data, that simply a query that hasn't run yet. Return a List, IEnumerable, an singular object, whatever you need, just make sure you execute that first by calling ToList() for example on your IQueryable expression first.
So, the steps are like this:
Setup your IQueryable first
Execute it by calling ToList(), First(), FirstOrDefault() whatever is appropriate and return the result of that.
I was trying to figure out some performance values of two scenarios. I thought I was only going to declare the obvious at first. But when I got the results I got a little confused. And now I am looking for a justification for the case.
I have a library which makes couple of queries through a MongoDb database and Active Directory services, then returns the results to client, which are:
GetUserType - to MongoDb - there is a collection which has username and type fields in its all documents. In the query I give the username and ask for the type field.
LoginCheck - to Active Directory - given the username and the password from the client, I create a PrincipalContext object to access to AD server and call ValidateCredentials upon it.
This job is performing on an existing MVC application at the moment. And we are going to create a new desktop application and employ it with the same job.
We were curios about how different can these two scenarios perform? We thought that a direct call to a library without any http connection would perform better than a service request without an hesitation. But we still wondered how much difference is there, and if it was acceptable we are going to make it work through the rest MVC service - because of reasons :)
Hence we tested out the following architectures:
Scenario 1:
Scenario 2:
Basically, what I do for performance test is this:
For scenario 1:
for(var i = 0; i<10000; i++)
{
new Class1().HeavyMethod();
}
For scenario 2:
// client side
for(var i = 0; i<10000; i++)
{
using ( var client = new HttpClient() )
{
var values = new Dictionary<string, string>();
var content = new FormUrlEncodedContent(values);
var response = client.PostAsync("http://localhost:654/Home/HeavyLift", content).Result;
var responseString = response.Content.ReadAsStringAsync().Result;
}
}
// MVC rest service
public class HomeController : Controller
{
public JsonResult HeavyLift()
{
return Json(new Class1().HeavyMethod(), JsonRequestBehavior.AllowGet);
}
}
Common Class:
public class Class1
{
public string HeavyMethod ()
{
var userName = "asdfasdfasd";
var password = "asdfasdfasdf";
try
{
// this call is to MongoDB
var userType = Personnel.GetPersonnelsType(userName).Result;
// this call is to Active Directory
var user = new ADUser(new Session
{
UserType = userType.Type,
UserName = userName,
Password = password
});
return userType.Type + "-" + user.Auth();
}
catch ( Exception e )
{
return e.Message;
}
}
}
The results for 10000 consecutive calls are confusingly shocking:
Scenario 1: 159181 ms
Scenario 2: 13952 ms
Scenario 1 starts off pretty quicly for the first few dosens of calls, then it starts to slow down.
Scenario 2 though offers a constant response time through 10k calls.
What is actually happening here?
Note: I checked the memory and cpu usages of the server that this scenarios runs on(everything runs on the same server) but there is nothing interesting actually, they are behaving just the same in terms of memory and cpu resources.
Here's my scenario:
I'm working with a .NET MVC 4.0 project, with a repository (as you'd expect), and trying to implement the Moq/xUnit testing libraries into a .NET Unit Testing project.
I've got this far:
MVC Controller
private IHOLService _service;
public PolicyController(IHOLService service)
{
_service = service;
}
public ActionResult Index()
{
var policies = _service.GetAllPolicies(100, 0).ToList();
return View(policies);
}
Unit testing class
[Fact]
public void GetPolicies()
{
// Arrange
var mockService = new Mock<IHOLService>();
List<Policy> policy = new List<Policy>()
mockService.Setup(cr => cr.GetAllPolicies(10, 0)).Returns(policy);
var controller = new PolicyController(mockService.Object);
// policy here contains 0 results.
// Act
var result = (ViewResult)controller.Index();
var model = result.ViewData.Model; // equals 0.
// Assert
var listCategories = Assert.IsAssignableFrom<List<Policy>>(result.ViewData.Model);
// listCategories.Count equals 0 results.
Assert.Equal(10, listCategories.Count); // Thus always fails
}
My problem is that when the Controller is called directly, everything works fine, 100 policies are loaded.
However, when I run the test, 0 products are loaded, in which I'm guessing is a problem with the mocking calls somewhere down the line, potentially to do with the service initialisation. Has anyone ever had this before and can offer advice?
Also, am I correct to test my Service, rather than my Repository held at data layer?
Thanks in advance.
In your test code, you initialize policy to an empty list, then tell your mock service to return this empty list. To make the test load policies, you need to put some policy instances into your policy list.
I would write a test which looks something like this:
[Fact]
public void GetPolicies()
{
// Arrange
var mockService = new Mock<IHOLService>();
Policy expectedPolicy = new Policy(); // substitute for the real way you construct these
List<Policy> policy = new List<Policy>() { expectedPolicy };
mockService.Setup(cr => cr.GetAllPolicies(10, 0)).Returns(policy);
// Act
var result = (ViewResult)controller.Index();
var model = result.ViewData.Model; // equals 0.
// Assert
var listCategories = Assert.IsAssignableFrom<List<Policy>>(result.ViewData.Model);
Assert.Equal(expectedPolicy, listCategories.First());
}
But it really depends on what aspect of your code you are trying to unit test. From what I can see, this test simply confirms that you are storing the Policy objects as expected. You might write further tests for any logic that depends on the Policy instances themselves.
I'm still trying to get my head around mocking. Right now, I'm trying to test my Save method on my UserService. As such, I'm mocking out my IRepository which my UserService class uses.
What I don't get is... if i normally save this user to my DB/Repository, it magically gets an Identity, which it then gets set, into my instance object. No rocket science stuff, here.
What I don't understand is, how do i mock this? should I care? I thought I should. Or.. is it that i don't care about that .. because I'm just making sure that the Repository method is called .. not so much that I get the correct data BACK from it.
Here's my pseudo unit test code. (unit test, not integration test .. hence the mock'd repository)...
[TestMethod]
public void GivenANewUserWithValidData_Save_ReturnsTheSameNewUserWithAUserIdDetermined()
{
// Arrange.
var const string passwordSalt = "V4BXAhmHq8IMvR7K20TgoQ=="
var user = new User
{
DisplayName = "Test",
Email = "foo#foo.com",
PasswordSalt = passwordSalt ,
Password = "foobar".ToSha2Hash(passwordSalt)
};
var mockUserRepository = new Mock<IRepository<User>>();
mockUserRepository.Setup(x => x.Save(It.IsAny<User>())).Verifiable();
// Configure this repo in our Dependency Injection.
ObjectFactory.Inject(typeof (IRepository<User>), mockUserRepository.Object);
// Act.
using (new TransactionScope())
{
UserService.Save(user);
UnitOfWork.Commit(); // <-- not sure about this.. currently it's still
// an EntityFramework context.
// I need to change this to.. something??
// Assert.
Assert.IsNotNull(user);
Assert.IsTrue(user.UserId > 0);
}
}
and the user service looks like this..
public class UserService : IUserService
{
public UserService(IRepository<User> userRepository,
ILoggingService loggingService)
{
// .. snip ..
public void Save(User user) { .. }
}
}
Any suggestions?
If you are unit testing UserService.Save(), then all your test should care about is that the repository is called. It's the responsibility of the repository tests to verify that an object is saved correctly.
That's actually something easy to do. You're setting up the Mock object like so:
mockUserRepository.Setup(x => x.Save(user)).Callback(() => user.UserId = 10);
// mocking the value of 10 being insterted into the key
You can even continue using It.IsAny() if you want in the setup, but basically all you need to do is attach the callback to the end of your setup method.
> 1) How should I test a [UserService.]Save method?
Should I care about the result? and
> 2) If i do care about #1 .. then how do i mock the
result also, so I can test that
If the repository is responsible to do the Identity-Magic then it makes no sense to mock this functionality in a test and then verify that this functionality has happened in the test. You want to test the UserService and not the IRepository-mock. The mock is there to crate a fake repository with just enought intelligence that the service does not crash and gets all requirements for the testcase. In this case I do not think that Identity-Magic is required by the service.
If the service is responsible to do the Identity-Magic then it makes sence to test if the id has been set.