The Art of Unit Testing: with Examples in .NET

Category: Programming
Author: Roy Osherove
4.5
All Stack Overflow 34
This Year Stack Overflow 1
This Month Stack Overflow 5

Comments

by anonymous   2019-07-21

As Steven has said, you're Asserting against the Mock NewsRepository in the above code.

The idea of mocking is to isolate the Code Under Test and to create fakes to replace their dependencies.

You use the Mock NewsRepository to test something that uses INewsRepository, in your case, you mention NewsService; NewsService will use your mock of INewsRepository.

If you search your solution for anything that uses INewsRepository.FindAll(), you will create a Mock Repository to test that code in isolation.

If you want to test something that calls your Service layer, you will need to mock NewsService.

Also, as Steven as said, there is no need for the NewsRepository to have a copy of itself injected by IoC, so:

public class NewsRepository : INewsRepository
{
   private readonly INewsRepository newsRepository;

   public NewsRepository(INewsRepository newsRepository)
   {
      this.newsRepository = newsRepository;
   }

   public IEnumerable<News> FindAll()
   {
      return null;
   }
}

should become:

public class NewsRepository : INewsRepository
{
   public IEnumerable<News> FindAll()
   {
      return null;
   }
}

Once you have functionality in your FindAll() method that needs testing, you can mock the objects that they use.

As a point of style from the great Art Of Unit Testing initialisation of mock objects is best left out of the Setup method and carried out in a helper method called at the start of the method. Since the call to Setup will be invisible and makes the initalisation of the mock unclear.

As another point of style, from that book, a suggested unit test naming convention is: "MethodUnderTest_Scenario_ExpectedBehavior". So,

FindAll_should_return_correct_news
could become, for example:
FindAll_AfterAddingTwoNewsItems_ReturnsACollectionWithCountOf2

I hope this makes the approach clearer.

by anonymous   2019-07-21

The single biggest issue I've faced using TDD is developers not being confident about unit testing. Poor unit testing wastes more time than it saves. Confused, untrustworthy, unmaintainable, unreadable tests fall by the wayside very quickly and jaded developers take time to want to unit test automatically again.

Per Fagrell makes some good points, especially about running the tests after every change; it should become second nature to run the tests before and after any test change.


Frameworks:

Consider QUnit as your framework for JS testing: http://docs.jquery.com/Qunit

I've got a test harness page with the dependent mark up and the tests run at page load very well.

You can follow the

  • Arrange
  • Act
  • Assert

flow for unit tests using QUnit.

However, you will have to manually have to implement test setup and teardown methods and call them in your test methods. These will help with the isolation of test cases by keeping the conditions indentical for all tests and prevent tests being dependent on the ordering of their running.

Look for useful frameworks in the other languages you will be using. NUnit is very popular for .NET.


Isolation:

Per Fagrell also makes a good point about isolation. The distinction between unit testing (testing one aspect of atom of functionality) and integration (testing how multiple atoms work together) should be thoroughly understood before beginning testing. If you have more than one assert in a test method, you are not unit testing and need to change your test method.


Conventions:

A good naming convention from the excellent The Art Of Unit Testing for your tests is MethodUnderTest_Condition_ExpectedBehaviour e.g.

Expand_TextVariable_ExpandsText

From the same book keep your tests:

  • Trustworthy
  • Maintainable
  • Readable

Otherwise you and other developers will not bother running the tests.


Fakes:

A common misunderstanding is the difference between the two types of fakes: stubs and mocks.

A seam is created in code by abstracting functionality that code depends on into an interface. E.g. A controller doesn't depend on a concrete repository, it will depend on an IRepository.

A stub then implements this IRepository and returns faked values; it is used to isolate the controller code to run in isolation. e.g. GetCustomer() will create a new customer and return that, with no calls to the real repository or any store. Stubs are never tested against.
A mock is like a stub except that it can hold values which can be tested against. e.g. AddCustomer(Customer customerToBeAdded), your mock will accept that value and can be asserted against. Mocks can be tested against.

Have a look at a Test Isolation Framework (or Mocking Framework), that can automatically create fakes for a given Interface.

A misunderstanding of the purpose of mocks has lead to more than one developer that I have seen create a mock to test functionality and then write tests against the mocks themselves.


Resources:

I've mentioned The Art Of Unit Testing and I recommend it thoroughly. It is one of the books, along with Code Complete, that I would grab if the office caught fire.

Hope that helps.

by anonymous   2019-07-21

You will have a hard time testing this method as it is. In fact I would recommend to learn more about unit testing and dependency injection before applying it to this code, unless you have time and motivation to jump right in and learn from your painful mistakes (as I did, when I started with unit testing).

The two gravest issues with your code are from my point of view:

  • The method is very long and does many different things. The shorter your code, the easier to test. Try to refactor separate concerns into their own classes (e.g. the e-mail sending code in the end). Then you can mock them in your tests for the current method and test the e-mail sending stuff in isolation.
  • You can hardly mock anything at this point, because the method creates all its collaborators itself. In order to mock anything, you have to be able to inject it. E.g., instead of creating the ReloadServiceRepository you could pass it as a parameter. Then you'd be able to pass a mock in your test, which behaves exactly, as you "told" him before.

I can recommend these books, if you want to learn more:

  • Roy Osherove's 'The Art of Unit Testing'
  • Mark Seemann's Dependency Injection in .Net

Take the time to learn some basics, and you will write much better tests faster.

by anonymous   2019-07-21

I'd recommend Roy Osherove's understanding Test Driven Development. At just over an hour, it's slightly longer than what you were asking for, but is a great introduction nonetheless.

I also recommend Roy's other videos too, his blog, ISerializable and his book, the art of unit testing.

by anonymous   2018-03-19

Why do we need to have automated unit testing? How effective is it?

Automated unit testing is very valuable first and foremost because it is automatable (normally, we only consider it a 'unit test' when it is automatable). As the size of an application grows, manually testing the whole application may take hours or even weeks. Even testing just a small part of an application takes time and is error-prone. Unless you are autistic, you will not be able to focus on performing each manual test 100% correctly if you have to do it over and over dozens of times.

In Agile development, we operate with the concept of Rapid Feedback: the sooner you can get feedback about what you did was right or wrong, the more effective you can be. We all make mistakes, but it is a lot less expensive to discover and fix a mistake thirty seconds after it was made, than several days or weeks later. That is why automated testing is so important.

While you can do automated testing on many levels, unit testing is the most efficient type to implement. It may be the most difficult testing discipline to understand and master, but it is much more robust than any other type of testing.

If I want to start doing automated unit testing. Where should I start from? (have heard about nunit)

First of all, you need to learn some unit testing basics. Roy Osherove's book The Art of Unit Testing is a good introduction.

When it comes to frameworks, NUnit has been around for a long time, but it has some inherent issues.

If you already have Visual Studio Professional or Team System, there's a built-in unit testing framework commonly known as MSTest. Most people dislike this framework, but personally, I find it quite adequate. The IDE integration works well, but the API could be better.

If you are looking for a free, open source unit testing framework, I would recommend xUnit.net, which is a much more modern framework.

Do I need to keep anything in mind when designing my classes to facilitate automated unit testing?

Yes, each class should be able to be used in isolation. This can be very hard to do by up-front design, or if you are trying to retrofit unit tests onto existing code, but should come more or less naturally if you adopt Test-Driven Development (TDD).

Does C# have an in-built support for automated unit testing?

No, C# is just a language, but as I mentioned above, certain versions of Visual Studio has MSTest.

Can we also test GUI with automated unit testing or is it just business logic?

Unit testing GUI tends to be very brittle (that is, test maintainance is very high), so is generally not a good idea.

However, there are many design patterns that can help you extract all GUI logic into testable classes: Modev-View-Controller, Model-View-Presenter, Application Controller, Model-View-ViewModel, etc.

You can perform automated tests of an entire application via such interfaces, bypassing only the GUI rendering part. Such tests are called Subcutaneous Tests, but are considered Integration Tests, not unit tests.

Have heard about mocking frameworks. Are they also for unit testing?

Dynamic mock libraries are only for unit testing.

Some good and popular ones are

  • Moq
  • Rhino Mocks
by anonymous   2017-08-20

I'd suggest you to read 'The Art of Unit Testing', by Roy Osherove. I strongly recommend you to read Parts 1 and 4.

Although focused on Unit Testing (duh) there are some well-explained concepts that really helped me to understand better the world of testing. It's not a complicated / boring book, I enjoyed reading it even without any previous testing knowledge. Hope you enjoy it too.

Rgds

by anonymous   2017-08-20

About unit testing here is very good book: http://www.amazon.com/Art-Unit-Testing-Examples-Net/dp/1933988274