Sid’s Blog

(life => life.make_it_better)

Unit Test and Test Driven Development in ASP.NET MVC application

| Comments

This article aims to summarize the concept of testing which can help you while writing tests using any framework out there. I will be writing more on this topic and will also attach any relevant demo applications on github. 

Types of Testing

There are many types of testing that you may want to apply to your application, namely:

  • Unit Test & Test Driven Development (TDD)
  • User Interface Testing
  • Integration Testing
  • Acceptance Testing 
  • Performance Testing
  • Accessibility Testing
  • Security Testing

Testing with ASP.NET Web Forms

If you are coming from ASP.NET Web Forms background and if you have done any testing in it, you may have find that it is not that easy to test your application because web forms aggregates and integrates the logic and the display i.e. view of your application. And this is what it makes testing very difficult.

Testing with ASP.NET MVC

The concept of Model View Controller (MVC) is designed by keeping testing in mind. The design of an application based on MVC concept makes an distinction to have a separate Model (data), the display of the application i.e. View and the Controller that has the logic to bind the Model to the View.

Below are some resources that you will need to test your MVC application:

  1. Visual Studio 2010/2012/Express 2013 (RC)
  2. One of any testing software framework - nUnit or xUnit or MSTest.
  3. Mocking Framwork - There are many free frameworks available out there but I’m going to use the free version of JustMock.
  4. You can also download nUnit Runner - that doesn’t depend on Visual Studio and runs independently.

Caveat

There are couple of Caveat that we need to discuss before discussing the key concepts of testing an application:

  1. There is no one right way to test.
  2. Testing is something relatively new in the software development industry and people have different views to how to organize your tests, code, etc. This subject is open to discussion.
  3. There is no one right way to refactor. You & your team should adapt the same pattern of the way to refactor so as to run on the same track and make a good design of your application.
  4. Best practices - even these are subjective. Stick to something what the community follows and then extend it as per your needs.

MVC and TDD

Unit Testing

  1. Test a single unit - a Class or (better) a method.
  2. Test in isolation of one another and to rest of the application. Test very small unit of functionality of your application.

TDD

  1. Uses Unit Testing to drive the design of your application.
  2. Is all about Test-First approach.
  3. There is a term referred as Red Green Refactor, which means

  4. Red Phase - create a failed test.

  5. Green Phase - write just enough code to pass the above failed test.
  6. Refactor Phase - clean up you code and then retest it to make sure your refactoring has not affected your test and it runs well.
  7. Repeat  - repeat the above process again from Red - Green - Refactor phase.

Robert C. Martin’s Laws - known as Uncle Bob in the community

Uncle Bob has mentioned three laws to keep in mind while writing a successful TDD:

  1. Write no production code until you have written a failing test.
  2. Write no more in your unit test then enough to make it fail.
  3. Write no more production code then enough to make it pass.

Key points to remember whilst you write your First Test

  1. Test one feature only.
  2. Write the above test, run it and see it fail. It’s very important to see it fail - because only by seeing it fail you can have the confidence when you see it pass that you have corrected the issue.
  3. Fix only enough so that your test can pass. It’s very important - don’t get ahead of yourself to make a pass for your test anyway. As,

  4. Remember YAGNI   - You Ain’t Gonna Need It . Sometimes you often end up working and spending time on something that you won’t need later, so, avoid that. 

  5. If no. 3 above is not followed then you are writing something which is not tested and may be will not be tested in the future as well as many of the code that you have written just makes pass for the test very easily.
  6. Run your test and see it succeed.
  7. Refactor and retest - to see your refactor has not broken the test.
  8. Repeat the whole process from no. 1 above.

Asserts

  1. It’s a way to see if you have in fact succeed i.e. what you expect to be true.
  2. Normally using any testing framework, you will find the keyword - “Assert” to make an assert of what you expect to be true.
  3. Rule to remember: You should have only one “logical” assert per test. It’s fine to have on or more assert statement but logically you should test just one thing and to ensure what is reason that your test should fail.
  4. There are many aspects that you can check while asserting namely,

  5. Equality - AreEqual, AreNotEqual, etc.

  6. Identity - AreSame, AreNotSame, Contains, etc.
  7. Condition - IsTrue, IsFalse, IsNull, IsNotNull, IsNan, IsEmpty, IsNotEmpty, etc.
  8. Type Checking - IsInstanceOf, IsNotInstanceOf, IsAssignableFrom, etc.
  9. Exception Throw or not thrown.
  10. String - Contains, StartsWith, EndsWith, AreEqualIgnoringCase, IsMatch (regex), etc.
  11. Collection - AllItemsAre… InstanceOfType, NotNull, Unique, Equal, Equivalent, etc.
  12. File - AreEqual, AreNotEqual, etc.
  13. Driectory - AreEqual, AreNotEqual, etc.
  14. Asserts to force a result - Assert.Pass, Assert.Fail, Assert.Ignore, etc.

Red - Green Refactoring Cycle

Red - Green Refactoring Cycle

But how do you Refactor ?

Uncle Bob says - Follow SOLID

  1. Single Responsibility: 

  2. Exactly one reason for a Class/method to change.

  3. One responsibility per Class/method.
  4. Open Closed Principle:

  5. Your Class should be open for extension, closed for modification.

  6. Creates dependable api to your Class.
  7. Derive but don’t modify internals of your Class.
  8. Liskov Substitution Principle:

  9. Ability to replace instances with their sub-types at run-time.

  10. Interface Segregation Principle:

  11. No client should be forced to depend on method it doesn’t use.

  12. Create small interfaces.
  13. Dependency Inversion Principle:

  14. Depend on abstractions and not on concrete implementation. This is the art of dependency injection.

Key points to remember whilst Refactoring

  1. Names matter

  2. Spend time while naming

  3. Renaming is very cheap - do it if you feel so.
  4. Use meaningful names.
  5. Don’t be afraid of long names.
  6. Make names pronounceable.
  7. Classes = Nouns
  8. Methods = Verbs
  9. Collections are plural.
  10. Avoid encoding:

    • No Hungarian Notation
    • Interfaces do not begin with I.
  11. Functions/Methods should be small.
  12. Do one thing & do it well.
  13. Avoid Switch Statements

  14. Use derived types where possible.

  15. Use Descriptive names - don’t be afraid of long names.
  16. Minimize number of parameters you pass to a method

  17. Zero is ideal

  18. One or two are workable
  19. Three or more are too much cognitive load of understanding how your method works and those parameters interact. 
  20. Don’t Repeat Yourself (DRY)
  21. YAGNI
  22. Structured Programming is dead - in a small method, multiple returns can clarify.
  23. Use fewer & smarter comments

  24. To explain intent when obscure.

  25. Use ToDo comments but no in production code.
  26. Avoid most comments and fix the code instead.
  27. The Law Of Demeter

  28. Modules should not know about innards of objects.

  29. Objects hide their data.
  30. Objects expose their public methods.
  31. Use Exceptions, not errors

  32. Don’t return null or pass null.

  33. Classes should be small.
  34. Single Responsibility should be applied to classes.
  35. Refactor your Tests by keeping FIRST in mind

  36. Fast

    • Test should run quickly else you won’t run it and then it has no value.
  37. Independent

    • Order of the tests must not matter.
    • No dependencies between tests.
  38. Repeatable

    • Running the same test twice should yield the same answer reliably.
  39. Self-Validating

    • Tests should return Boolean: Pass or Fail but no ambiguity.
  40. Timely

    • Tests should be written just before production code.

This was all about the concepts that you should keep in your mind while writing programs. Practice the above in your daily work and you will notice the difference it makes in your way to write applications.

Stay tuned for sample application to write tests with MVC.

Comments