Unit Testing for VS2017 project - c#

I have an ASP.NET application (a basic form where I capture some input) in VS2017.
One of the fields on the form is Mark, which is an integer.
I have the following block of code for the Mark, in my .cs file.
[Display(Name = "Mark")]
[Range(1, 10, ErrorMessage = "Mark must be between 1 and 10")]
public int Mark{ get; set; }
I've created a MSTest project for this application to write Unit Tests.
My question is, do you write Test Cases for this block to verify the input value is in the expected range?
If yes, how you write that?
I've started with this.
[DataRow(0, "Mark must be between 1 and 10")]
[DataRow(11, "Mark must be between 1 and 10")]
[DataTestMethod]
public void TestMark_IsMarkValid_NotValid(int mark, string expectedMsg)
{
//Arrange
Student testStudent = new Student();
testStudent.Mark = mark; //this does not throw any error, although the assigned value is outside of the defined range. But it looks like the range validation only applies to the webform.
//Act
string actualMsg = "Mark must be between 1 and 10"; //this is not correct. I was thinking to capture in the actual result the error message yield by the Range validation, but assigning a value outside range doesn't yield any error message.
//Assert
Assert.AreEqual(expectedMsg, actualMsg);
}
Now, not sure if that block should be in scope for unit testing. If it should be, I have a feeling the approach I've taken is not correct.
Any thoughts, please?
Many thanks,
Cosmin

Interesting question. I'm not certain that there is a definitively correct answer. But here are my thoughts :
1) "Mark" is a property. We don't need to unit test a property because Microsoft have already tested that properties work.
2) The attributes do not affect the property, but provide information about the property that others can use. That is why your unit test passes the test for the value. The form uses the attributes, your unit test does not. That is why your unit test can assign any value.
3) If you really want to limit the value of the variable then limit it in the Student class - either by a setter or else explicit get/set and a backing variable - you can never trust any data submitted by the browser.
4) Testing a UI is not easy. We have a test team that tests by hand. We have tried several tools but none is outstanding. Keep your business logic out of your UI and put it in business classes where it can be easily tested.
So, to answer your question, I personally would not test that the attribute functions in a unit test.
I hope that helps.

Related

Required fields for Unit Testing in c#

I have an application form in my project and I want to write unit tests.
My code behind has required fields for server side validation to ensure the field is not blank. I need help to know if I've written this right because this is only my second day of writing unit test. please be nice i am only 13.
[Required(ErrorMessage = "Please provide a title")]
public string Title
{
get; set;
}
Then in my unit test I did
public void TitleIsNotBlank()
{
Assert.IsNotNullOrEmpty(_vm.Title);
}
Would this check that field is not blank?
It's important to understand that the [Required] attribute only decorates the property but it does NOT automatically validate it unless something calls upon its functionality.
By decorating the property, you are telling any other process that may inspect it that it should be required and what the error message should read. The MVC framework's validation, for instance, fires the validation within this attribute for you. That's when validation actually occurs.
In my opinion, this should ideally be tested at the business object level (when you actually assign the value of the model to an object and try to do something with it, like save it).
The assumption is that the attribute's validation code has been tested, so you don't need to. However, since your goal is to increase coverage, what you can do is test to make sure the field is "marked" as required by inspecting it and making sure it is decorated as such:
var type = typeof(YourModelClass);
var property = type.GetProperty("Title");
var attributes = (Required[])property.GetCustomAttributes(typeof(Required), false);
Assert.IsTrue(attributes.Length > 0);

Make sure/check if property is selected in linq .Select() statement with unit test?

Assume I have the following class:
public class Person
{
public string FirstName{get;set;}
public string LastName{get;set;}
public int Age{get;set;}
}
Assume I have this query:
var persons = someListOfPersons.Where(r => r.Age > 18)
.Select(m => new Person(){LastName = m.LastName});
As we can see above, I am selecting new Person objects with only the LastName property actually selected. Note that at this point this is still just an IQueryable.
How can I unit test this, to make sure that the LastName property has been included in the select statement?
I would focus on testing the actual behavior of the piece of code you are trying to test through its public contract. Testing implementation details like the type of returned objects, whether a getter was called, etc. ties your tests very close to the implementation, which means that any change in the code will require a change in the tests. This is something you want to minimize, or the cost of maintaining your unit tests will rise. You can find a nice article about testing behavior instead of implementation details here.
Just as Leslie Davies mentions, I would also provide a dummy list of persons in my test and check whether the piece of code correctly returns only the last names of persons that are over 18.
Sidenote: If it's important that you only expose the last names through this piece of code, why not redesign the code so that it only returns names instead of incomplete Person objects? Returning Person objects that are only partly initialized may lead to confusion further down the road.

basic assertions about unit testing

Given the function below - would I be able to assert if the Value "value" was deleted from the user? Or is that assertion part of the tests on the UserService?
Also, what assertions could I test from the function?
public IHttpActionResult Post(string value)
{
var user = authorizationService.GetCurrentUser();
var isDeleted = userService.DeleteValue(value, user);
if (!isDeleted)
{
return NotFound();
}
userService.DeleteProperty(value, user);
var identityResult = userService.Update(user);
if (identityResult.Succeeded)
{
return Ok();
}
return InternalServerError();
}
Yes, you can test that: a unit test doesn't have to be the smallest possible unit per sé but that it may also contain another unit inside of it. By writing tests for both these scenarios you're essentially making a layered project where you have separate tests for the different layers and the value they add to your chain.
You could make the analogy with VAT in a production chain where each test will test the value added in each segment. More information on that here.
This translates to your question as: yes, you can (and should) test whether this action method does what it is supposed to do.
A few examples of tests you could do:
value is null
value is not in the expect format (numeric, negative value, special characters)
The user is not found
a valid value will display Ok()
What you will have to do is make sure that you are not testing against a production database but instead use in-memory repositories (mocking, faking, stubbing, seaming, you name it).
By having these tests in your controller and inside your userService you will know the exact location of the problem in case it isn't working as you want it to:
Test for: Controller Service Conclusion
Works Works Works
Works Doesn't work Faulty tests
Doesn't work Works Controller test failed
Doesn't work Doesn't work Service test failed
While not writing a test for the controller but instead relying on the service would not give you the information that your code actually works.
The line between unit-testing and other types (integration and acceptance testing mainly) is thin because you're testing a bigger part of the system but I still consider it unit-testing since it is contained to the logic of your application and does not use any external resources (database calls get mocked/stubbed/...).

Having difficulties setting up a mock to unit test WebAPI Post

I'm attempting to set up a unit test with MSTest and Moq for a live system that posts json from a form to a database. The system itself works just fine, but I've been tasked with attempting to build some tests for it. The ajax call in the view I'm working with goes to following HttpPost method one of the controllers:
[HttpPost]
public ActionResult Add(Request model)
{
return ProcessRequest(model, UserAction.Create);
}
Which leads to the WebAPI controller:
public int Post([FromBody]Request value)
{
try
{
var id = myRepository.AddRequest(value);
foreach (var day in value.Days)
{
day.RequestId = id;
myRepository.AddRequestDay(day);
}
return id;
}
catch
{
return -1;
}
}
With my test, I thought that using TransactionScope would be a good idea so I'm not actually saving any data on the database. If there is a better approach, please enlighten me:
[TestMethod]
public void API_Request_Post()
{
using (TransactionScope ts = new TransactionScope())
{
var jsonObject = //some json scraped from a test post
var request = new Mock<HttpRequestBase>();
//This is where I'm stuck. I can't find anything in Setup that lets me prep the Post body for when the controller gets to it.
//request.Setup(x => x.InputStream).Returns(jsonObject);
RequestController controller = new RequestController();
//This is another point that I don't understand. I make the call for post happy with a reference to the model instead of the actual json?
var result = controller.Post(new Models.Request() );
Assert.IsTrue(result > -1);
}
}
Any help trying to determine what part of the HttpRequest I need to give my json to would be greatly appreciated (and helping me understand the Post would just be icing on the cake).
Aside
I hope I'm not telling you something you already know, but it looks like you are maybe questioning where to start? That is the hardest part of testing...
Just to make sure we are on the same page, the key to knowing what to test is describing the scenario, and the key to unit testing that scenario is Isolation.
What this means is you want to isolate in regard to the class "under test".
Also, code is much easier to test if you write the test first and then the code to make that pass. You're not in that situation, so that means that the code you have MAY NOT be testable without changing it.
And finally, given any external / 3rd party system, unless you are doing an "exploratory test" then you do not want to test 3rd party stuff, namely, http posting / getting. Instead, you want to test your code and how it performs.
Assuming you knew that or that all makes sense, then, this part will be be obvious too.
Moq, or any other mocking framework, is designed to stand in for objects / services that your class under test collaborates with, in order to aid in isolation. Given two classes, ClassA and ClassB, where ClassA acts on ClassB, you want to fake/mock Class B when giving it to ClassA so you can assert / verify that ClassA behaves as you would expect for the given scenario. This seems naive at first, but consider that you will also do the same for ClassB, you then have a suite of tests that isolate in respect to what they are testing, and that gives you great coverage.
And the key to isolation is injection, make sure that if ClassA acts on ClassB, you pass ClassB in to ClassA's constructor, that way you can give it a fake class B. Class B shouldn't do anything, other than respond how you say it should respond so you can prove that ClassA behaves appropriately in that situation.
Some people frown on changing code to make it testable, but my argument is if you wrote the code to be testable in the first place, you wouldn't have to change it, so try to refactor but not reengineer.
What to Test
So, what that means is you will want a few different scenarios, each with each tests that isolate in respect to what you care about.
The key to good tests is figuring out what it is you want to test, and then arranging your tests so that it is clear what you are doing.
Test Class Name DOES NOT need to have "Test" in it; that's redundant. Explain what the scenario is instead; who is involved, etc.
The Test Method should say what the action is that you care about testing; what states are you in, etc.
** Inside the method** for now follow the "Arrange, Act, Assert" (aka Given, When, Then) approach:
Arrange: set up all of your mocks or any variables you need here, including the one class you are testing, such as your real Controller but fake myRepository and fake value
Act: do the actual action, such as Post()
Assert: Prove that the behaviors you expected happened, such as when you give it a value with four days, then you expect that:
myRepository was told to add the value
myRepository was told to add a day four times
An Example
As I'm not entirely sure what the intent of the test is there, and I don't know all of the code, I'm going to give an example that I think will relate well and will hopefully also show how to set up the mocks (and ideally why you would!)
Also if this were truly a unit test, you would usually strive for one test per assertion / verification so you do not have to debug the test, only the failing code, but I'm putting three in here for "simplicity".
In this test, you'll see that I:
Care about testing the logic in POST
So I create a mocked repository that is only used for verification it was called,
And a mocked Request that is setup to respond appropriately when called,
And I pass the mocked repository to the Controller's constructor (isolation through injection)
And then I perform the action I care about, POST, on the live controller with mocked collaborators (repository and request),
And then I verify that POST performs / behaves as expected.
[TestClass]
public class GivenAValidRequestAndRepository(){
[TestMethod]
public void WhenWeReceiveAPostRequest(){
//Arrange / Given
var repository = new Mock<IRepository>();
var request = new Mock<IRequest>();
request.Setup ( rq => rq.ToString() )
.Returns ( "This is valid json ;-)" );
request.Setup ( rq => rq.Days )
.Returns ( new List<IDay> {
"Monday",
"Tuesday",
} );
var controller = new RequestController( repository.Object );
//Act / When
int actual = controller.Post( request.Object );
//Assert / Verify
// - then we add the request to the repository
repository.Verify(
repo => repo.AddRequest( request, Times.Once() );
// - then we add the two days (from above setup) in the request to the repository
repository.Verify(
repo => repo.AddRequestDays( It.IsAny<IDay>(), Times.Exactly( 2 ));
// - then we receive a count indicating we successfully processed the request
Assert.NotEqual( -1, actual );
}
}
Closing
Your goal should not be to make your boss happy that you have written a test. Instead, strive for valuable and expressive tests that you will be able to maintain down the road. You won't get it perfect (nor should you try) just make sure that what you are testing adds value. Cover things that if they were to change in code, your test would then fail, indicating you have a bug.
I hope this helps, please reply with comments / questions.

Are those unit tests fine?

I'm trying to grasp test driven development, and I'm wondering if those unit tests is fine. I have a interface which looks like this:
public interface IEntryRepository
{
IEnumerable<Entry> FetchAll();
Entry Fetch(int id);
void Add(Entry entry);
void Delete(Entry entry);
}
And then this class which implements that interface:
public class EntryRepository : IEntryRepository
{
public List<Entry> Entries {get; set; }
public EntryRepository()
{
Entries = new List<Entry>();
}
public IEnumerable<Entry> FetchAll()
{
throw new NotImplementedException();
}
public Entry Fetch(int id)
{
return Entries.SingleOrDefault(e => e.ID == id);
}
public void Add(Entry entry)
{
Entries.Add(entry);
}
public void Delete(Entry entry)
{
Entries.Remove(entry);
}
}
Theese are the unit tests I have written so far, are they fine or should I do something different? Should i be mocking the EntryRepository?
[TestClass]
public class EntryRepositoryTests
{
private EntryRepository rep;
public EntryRepositoryTests()
{
rep = new EntryRepository();
}
[TestMethod]
public void TestAddEntry()
{
Entry e = new Entry { ID = 1, Date = DateTime.Now, Task = "Testing" };
rep.Add(e);
Assert.AreEqual(1, rep.Entries.Count, "Add entry failed");
}
[TestMethod]
public void TestRemoveEntry()
{
Entry e = new Entry { ID = 1, Date = DateTime.Now, Task = "Testing" };
rep.Add(e);
rep.Delete(e);
Assert.AreEqual(null, rep.Entries.SingleOrDefault(i => i.ID == 1), "Delete entry failed");
}
[TestMethod]
public void TestFetchEntry()
{
Entry e = new Entry { ID = 2, Date = DateTime.Now, Task = "Testing" };
rep.Add(e);
Assert.AreEqual(2, rep.Fetch(2).ID, "Fetch entry failed");
}
}
Thanks!
Just off the top of my head...
Although your testing of add really only tests the framework:
You've got adding 1 item, that's good
what about adding LOTS of items
(I mean, ridiculous amounts - for what value of n entries does the container add fail?)
what about adding no items? (null entry)
if you add items to the list, are they in a particular order?
should they be?
likewise with your fetch:
what happens in your fetch(x) if x > rep.Count ?
what happens if x < 0?
what happens if the rep is empty?
does x match performance requirements (what's it's algorithmic
complexity? is it within range when there's just one entry and when
there's a ridiculously large amount of entries?
There's a good checklist in the book Pragmatic Unit Testing (good book, highly recommended)
Are the results right?
Are all the boundary conditions CORRECT
Conform to an expected format
Ordered correctly
In a reasonable range
Does it Reference any external dependencies
Is the Cardinality correct? (right number of values)
does it complete in the correct amount of Time (real or relative)
Can you check inverse relationships
Can you cross check the results with another proven method
Can you force error conditions
Are performance characteristics within bounds
Here's some thoughts:
Positive
You're Unit Testing!
You're following the convention Arrange, Act, Assert
Negative
Where's the test to remove an entry when there's no entry?
Where's the test to fetch an entry when there's no entry?
What is supposed to happen when you add two entries and remove one? Which one should be left?
Should Entries be public. The fact that one of your asserts calls rep.Entries.SingleOrDefault suggests to me you're not constructing the class correctly.
Your test naming is a bit vague; typically a good pattern to follow is: {MethodName}_{Context}_{Expected Behavior} that remove the redundancy "test" redundancy.
As a beginner to TDD I found the book Test-Driven Development By Example to be a huge help. Second, Roy Osherove has some good Test Review video tutorials, check those out.
Before I answer, let me state that I am fairly new to unit testing and by no means an expert, so take everything I state with a grain of salt.
But I feel that your unit tests are largely redundant. Many of your methods are simple pass through, like your AddEntry method is simply a call to the underlying List method Add. Your not testing your code, your testing the Java library.
I would recommend only unit testing methods that contain logic that you write. Avoid testing obvious methods like getters and setters, because they operate at the most basic level. That's my philosophy, but I know some people do believe in testing obvious methods, I just happen to think it is pointless.
Seems fine like this. I personally like to give my tests a bit more descriptive names but that's more of a personal preference.
You can use mocking for dependencies of the class you're testing, EntryRepository is the class under test so no need to mock that, else you would end up testing the mock implementation instead of the class.
Just to give a quick example. If your EntryRepository would use a backend database to store the Entries instead of a List you could inject a mock-implementation for the data-access stuff instead of calling a real database.
This looks like a fine start, but you should try to test the 'borderline' cases as much as possible. Think about what might cause your methods to fail - Would passing a null Entry to Add or Delete be valid? Try to write tests that exercise every possible code path. Writing tests in this manner will make your test suite more useful in the future, should you make any changes to the code.
Also, it is useful for each test method to leave the test object in the same state as when it was invoked. I noticed your TestFetchEntry method adds an element to the EntryRepository, but never removes it. Having each method not affect test object state makes it easier to run series of tests.
You should not be mocking the IEntryRepository since the implementing class is the class under test. You might want to mock the List<Entry> and inject it, then just test that the methods that you invoke via your public interface are called appropriately. This would just be an alternative to the way you have it implemented and isn't necessarily better -- unless you want the class to have it's backing class injected in which case writing the tests that way would force that behavior.
You might want some more tests to make sure that when you insert an entry, the right entry is inserted. Likewise with delete -- insert a couple of entries, then delete one and make sure that the proper one has been deleted. Once you come up with tests to get the code to do what you want it to, keep thinking of ways that you could mess up writing the code and write tests to make sure those don't happen. Granted this class is pretty simple and you may be able to convince yourself that the tests you have that drive behavior is sufficient. It doesn't take much complexity, though, to make it worth testing edge cases and unexpected behavior.
For a TDD beginner and for this particular class, your tests are fine. +1 for making the effort.
Post another question once you get to more complex scenarios involving dependency injection and mocking. This is where things get really interesting ;).
Looks good overall. You should use transactions (or create new instance of repository in TestInitialize) to make sure the tests are trully isolated.
Also use more descriptive test methods, like When_a_new_entity_is_added_to_a_EntryRepository_the_total_count_of_objects_should_get_incremented

Categories