0

I'm not in the field, so I don't have any professional experience from projects following the TDD design. I am trying to adopt this pattern, but I'm confused as to when I start actually writing the tests. In my example, a personal blogging app. I'm starting from complete scratch using ASP.NET 5, MVC 6. I've built the main functionality such as displaying the homepage, allowing login using Identity, allowing the posting of a blog post, and retrieval of those blog posts through an MVC controller as well as an API.

This is all done using the Repository pattern, and MVVM.

At what point in that process should I really begin testing?

Do I test that the repository does what it should do? That smells weird to me, since repositories are injectable.

Do I test that the ViewModel has certain properties?

Or is it acceptable to simply start with testing whether a valid ViewModel allows creation of a new BlogPost, and an invalid does not?

scrapcode
  • 41
  • 3
  • 5
    In TDD, you write the test to describe the method's behavior, and then you write the method. So the short answer to the title of your question is: immediately. – Robert Harvey Jan 23 '16 at 15:53

3 Answers3

5

TDD revolves mostly around unit testing, this answer is going to cover that.


Why do you make applications? Do you make them to see see that C# works well, or do you make them to solve a problem presented by your client (be aware, sometimes the client may as well be you)?

Unless you are a .NET developer working for the Microsoft company and are actually responsible for maintaining the C# language, it is almost always the second case. You are trying to solve a problem, a problem, which has some rules.

The rules presented to you are your business logic, your domain. Once you start working on your domain, that is the latest when you should start writing tests.

Latest? Yes. Speaking from a position of a senior PHP developer, even though it is nice that PHP allows you to do a lot of stuff a compiled language would not (such as returning two completely different objects from a method), it leads to bad code. Hence in many cases, it is better to just write your database layer and not be dependent on an already existing solution with static methods etc. If you do build this layer, you might consider writing tests for that as well, to make sure what you wrote works.

Generally speaking, there's never too early to start writing unit tests, but there's a point where it becomes too late and unnecessary. Such as unit testing your controlers. I have seen people do that and that is not what unit test should do. Your controllers are a procedure, containing factories for services, instantiating them, working with your domain objects, they are not units. If you want to test your controllers, use integration test suites instead.

What should always be tested then?

You want to have unit tests for your domain, your business logic. If you have that and your business rules are indeed only there, you do not really need to worry about the rest of the application, as it should only perform basic CRUD operations on data, which is valid (thanks to tests and good domain models).

TDD From the life-cycle point of view

TDD means you write tests first and then you write code. When you are working on a project, you go through several stages.

  1. Chosing the right technology - You do not know which programming language you are going to choose, yet, thus cannot simply write tests.
  2. Chosing your architectural model - You chose the programming language, but have no idea how your project will be structured. Will it be modules, services, MVC? In your case it is most likely going to be the MVVM pattern. Is your whole architecture considered a unit? I don't think so. You do not need to test architecting your application.
  3. Designing your domain layer - this is the part, where you take user functional and non-functional requirements along with the rules from the client and implement them. Before this stage you are supposed to write tests and then provide implementation to make them pass.
  4. (optional) Designing services, which use your domain models - You may create services uniting more domain operations into one process, much like a facade. You may write tests before designing these services, but it's an optional task.

As said before, to make sure your application (the wiring part) works as intended, you should use integration tests instead of unit testing.

Andy
  • 10,238
  • 4
  • 25
  • 50
1

At what point in that process should I really begin testing?

Well, you asked specifically about , so there's really only one correct answer: Before you do anything else.

Test-Driven Development and Design is called Test-Driven, because the Tests drive the development and design. The tests tell you when to start writing code. They tell you what to write. They tell you how to write it. They tell you what to write next. Very importantly, they tell you when you are done writing.

In order to do that, they have to exist. The very first thing you do, before you do anything else, is writing a test.

Note: I'm not saying that this is the only way to go about this, but you asked about TDD, and if you don't follow this, then it's not TDD.

The general TDD cycle looks like this (it's actually 4 cycles, nested 3 levels deep):

  1. Pick a user story (how you do this is outside the scope of TDD, you can use Scrum or XP, for example, for figuring out which story to pick next).
  2. Write the simplest acceptance test that could possibly fail for the acceptance criteria of that user story.
  3. Run your acceptance tests.
  4. Watch the acceptance test (and only that test!) you just wrote fail.
  5. Verify that it fails for the right reasons.
  6. As long as the test fails, repeat:

    1. Pick an independent unit of behavior
    2. Write the simplest unit test that could possibly fail for that unit of behavior
    3. Run your unit tests.
    4. Watch the unit test (and only that test!) you just wrote fail.
    5. Verify that it fails for the right reasons.
    6. As long as the test fails, repeat:

      1. Write the simplest code that could possibly change the error message
    7. As soon as the test passes, as long as there is something to improve, repeat:

      1. Refactor Mercilessly

Keith Braithwaite has created an exercise he calls TDD As If You Meant It. It consists of a set of rules (based on Uncle Bob Martin's Three Rules of TDD, but much stricter) that you must strictly follow and that are designed to steer you towards applying TDD more rigorously. It works best with pair programming (so that your pair can make sure you are not breaking the rules) and an instructor.

You can read about it more in these two questions:

Jörg W Mittag
  • 101,921
  • 24
  • 218
  • 318
0

Usually you can't write a test for a method before at least the declaration of the method has been written, because the test won't compile. And you can't run the test before at least an empty definition for the method is written, because the test won't link. So the best order is:

(a) Plan what you want to do. (b) Write the declaration for the method. (c) Write the unit test. (d) Write an empty definition of the method. (e) Run the unit test, making sure that a failure is reported. (f) Implement the method. (g) Run unit tests again to make sure that they succeed. (h) With your new insight into the problem improve the unit tests, and improve the method as needed.

gnasher729
  • 42,090
  • 4
  • 59
  • 119
  • Compile and/or link errors count as test failures. You should always start with the simplest test that could possibly fail, followed by the simplest code that could possibly change the message. So, say you are TDDing a `Stack` data structure. Your first test is going to be `aStack.push(null);`. Which gives you an "undeclared variable `aStack` error". So, you add `let aStack = null;` directly above. Now the error is a `NullReferenceError`. So, you change to `let aStack = {};`. Which will give you a `NoMethodError`. You add the method declaration, which gives you a `LinkError`. You add the body – Jörg W Mittag Jan 24 '16 at 02:32
  • … which will now have the test passing. (Since you have no assertions.) The next step is to write a new test which actually asserts something, like `assert aStack.push(null).pop() == null;`. Depending on how you implemented the trivial method body in test 1, this may actually succeed, if not, you just add `return null;`. Next test would be `push`ing something other than `null`, which actually forces you to implement a backing field. And so on. But you can certainly start with calling a non-existant method, in fact, that is how you drive (the middle "D") your API design through tests. – Jörg W Mittag Jan 24 '16 at 02:35