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.
Related
I want to test that a bunch of buttons on screen are responding properly, this amount this increase dynamically thought the project and will be used in more than a single test.
My first try was using [TestCase] attribute
[TestCase("High action - Button")]
[TestCase("Low action - Button")]
[TestCase("Right action - Button")]
[TestCase("Left action - Button")]
public void WhenClickOnActionButtons_ActionStreamShouldIncrease (string buttonNameInScene)
But this means that every time that some buttons were added I would need to remember to come back to every test that use the buttons and manually add the new test case
Then I thought that have a container that control the buttons would solve my problem, I will lost the possibility to see which buttons caused the error in the test suite, but this can be fixed just by adding a simple message into the assert
[Test]
[Order(1)]
public IEnumerator WhenClickOnActionButtons_ActionStreamShouldIncrease ()
{
foreach (var battleActionButton in battleActionButtons) // <- Buttons containers
{
// Arrange
var changedWhenClicked = false;
battleActionButton.GetComponent<Button>().onClick.AddListener(() => changedWhenClicked = true);
// Act
var positionOfButtonInScreen = Camera.main.WorldToScreenPoint(battleActionButton.transform.position);
LeftClickOnScreenPosition(positionOfButtonInScreen);
yield return null;
// Assert
Assert.True(changedWhenClicked, $"{battleActionButton.name} didn't pressed correctly");
}
}
But now if the button container is empty the test pass, so I thought, let's create a test that runs before it to check if the container is empty
[Test]
[Order(0)]
public void ActionButtonsGroup_IsGreaterThan0()
{
// Arrange
// Act
// Assert
Assert.That(battleActionButtons.Count, Is.GreaterThan(0));
}
But then, if empty, this fails, and the next pass, so I thought, maybe I could make the tests stop running when a test fails, but then I discovered that a test should not rely on other tests, so my question is, how should I handle this kindle of case?
This sounds like a case for using a proper collection as a data source for a parametrised test. In NUnit you can use TestCaseSource for this:
[TestCaseSource(typeof(BattleActionButtons))]
public void ButtonTest(BattleActionButton button)
{
// Test body goes here...
}
where BattleActionButtons is a real class:
public sealed class BattleActionButtons : IReadOnlyCollection<BattleActionButton>
{
private readonly List<BattleActionButton> buttons = new();
public BattleActionButtons()
{
// Add buttons here...
}
public int Count => buttons.Count;
public IEnumerator<BattleActionButton> GetEnumerator()
{
return buttons.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Perhaps BattleActionButtons is just a test-specific class, but perhaps it would make sense in the production code as well..(?) With TDD, it often happens that you introduce an abstraction to factor your tests in a nice way, only to discover that this abstraction is of general usefulness.
If you're concerned that BattleActionButtons is empty, write another test that verifies that this isn't the case:
[Test]
public void ButtonsAreNotEmpty()
{
Assert.IsNotEmpty(new BattleActionButtons());
}
There's no need to order the tests. If BattleActionButtons is empty, ButtonsAreNotEmpty will fail. It's true that the data-driven parametrised test (here called ButtonTest) will pass when the collection is empty, but there's nothing wrong in that. It just becomes a vacuous truth.
(Unit tests are essentially predicates, and a parametrised test is a universal claim that states that for all (∀) values in the data source, the predicate holds. Thus, when the data source is empty, any test is trivially going to pass, which is exactly as it should be according to predicate logic.)
You can put the assertion from the second test before the foreach loop:
[Test]
[Order(1)]
public IEnumerator WhenClickOnActionButtons_ActionStreamShouldIncrease ()
{
// Precondition
Assert.That(battleActionButtons.Count, Is.GreaterThan(0));
foreach (var battleActionButton in battleActionButtons) // <- Buttons containers
{
// Arrange
var changedWhenClicked = false;
battleActionButton.GetComponent<Button>().onClick.AddListener(() => changedWhenClicked = true);
// Act
var positionOfButtonInScreen = Camera.main.WorldToScreenPoint(battleActionButton.transform.position);
LeftClickOnScreenPosition(positionOfButtonInScreen);
yield return null;
// Assert
Assert.True(changedWhenClicked, $"{battleActionButton.name} didn't pressed correctly");
}
}
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.
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 trying to become more familiar with the Rhinomocks framework, and I'm trying to understand the Expect methods of rhinomocks.
Here's a unit test I have written:
[TestMethod]
public void Create_ValidModelData_CreatesNewEventObjectWithGivenSlugId()
{
//Arrange
var eventList = new List<Event>() { new Event() { Slug = "test-user" } };
_stubbedEventRepository.Stub(x => x.GetEvents())
.Return(eventList);
_stubbedEventRepository
.Expect(x => x.SaveEvent(eventList.SingleOrDefault()))
.Repeat
.Once();
var controller = new EventController(_stubbedEventRepository);
EventViewModel model = new EventViewModel();
//Act
//controller.Create(model); COMMENTED OUT
//Assert
_stubbedEventRepository.VerifyAllExpectations();
}
I thought I understood this code to only pass if the SaveEvent(...) method get's called exactly once. However, with controller.Create(model) commented out, the test still passes. Inside controller.Create(model) is where the SaveEvent() method gets called.
I tried the following:
_stubbedEventRepository
.Expect(x => x.SaveEvent(eventList.SingleOrDefault()));
But it still passes every time, so what am I doing incorrectly stack overflow? The sources I have looked at online haven't been able to help me. Why is VerifyAllExpectations() yielding a successful unit test?
Thank you!
Here's the body of the controller constructor:
public EventController(IEventRepository eventRepository)
{
_eventRepository = eventRepository;
}
edit:
// member variables
private IEventRepository _stubbedEventRepository;
[TestInitialize]
public void SetupTests()
{
_stubbedEventRepository = MockRepository.GenerateStub<IEventRepository>();
}
If you want to verify the behavior of the code under test, you will use a mock with the appropriate expectation, and verify that. If you want just to pass a value that may need to act in a certain way, but isn't the focus of this test, you will use a stub.
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.