TDD: How to correctly implement?

  • (2 Pages)
  • +
  • 1
  • 2

21 Replies - 727 Views - Last Post: Yesterday, 10:48 PM

#1 November-06  Icon User is offline

  • D.I.C Regular

Reputation: 46
  • View blog
  • Posts: 407
  • Joined: 04-January 11

TDD: How to correctly implement?

Posted 21 November 2014 - 01:24 AM

I created a basic unit test project. The order that I did it is different from what is being recommended in internet articles.

I have read that for TDD, you should write unit test first before programming the code. In my case, I was just trying to create a unit test project without TDD in mind, so I created the application first before writing the test.

I have been reading on TDD earlier and so I have decided to create a new test project. But I can't call classes and functions in my application that I can compare in the Assert method if I don't write at least the classes and methods in my application.

So, please tell me if I understand TDD right. This may not sound like the complete TDD itself. I just want to know if my simple understanding of how to start it is correct.

Here's how I am planning to start:
  • Create application and write basic methods and functions structure without really coding the implementation
  • Create test project to call the units of the application to be tested (Without the implementation, test should fail)
  • Add correct code implementation to see if tests will succeed
  • Add or refactor test methods as needed


Anything to correct or add? Anything I misunderstand?

Feel free to post your suggestions. My idea might be to simple and too basic but I am hoping to learn to write a good unit test using the TDD approach.

Is This A Good Question/Topic? 0
  • +

Replies To: TDD: How to correctly implement?

#2 cfoley  Icon User is offline

  • Cabbage
  • member icon

Reputation: 2069
  • View blog
  • Posts: 4,307
  • Joined: 11-December 07

Re: TDD: How to correctly implement?

Posted 21 November 2014 - 02:30 AM

Quote

I have been reading on TDD earlier and so I have decided to create a new test project. But I can't call classes and functions in my application that I can compare in the Assert method if I don't write at least the classes and methods in my application.


A failure to compile is a failing test. In Java, I can write:

@Test
public void firstIsMax() {
  max(5, 4);
}


The max() method doesn't exist so it doesn't compile and the test fails. I make it pass by doing this:

@Test
public void firstIsMax() {
  max(5, 4);
}

int max(int x, int y) {
	return -1;
}


Now I add the next little bit of test which fails:

@Test
public void firstIsMax() {
  assertEquals(5, max(5, 4));
}

int max(int x, int y) {
	return -1;
}


and I make it pass:

@Test
public void firstIsMax() {
  assertEquals(5, max(5, 4));
}

int max(int x, int y) {
	return x;
}


Now I write the next test which fails:

@Test
public void firstIsMax() {
  assertEquals(5, max(5, 4));
}

@Test
public void secondIsMax() {
  assertEquals(6, max(5, 6));
}

int max(int x, int y) {
	return x;
}


and I make it pass:

@Test
public void firstIsMax() {
  assertEquals(5, max(5, 4));
}

@Test
public void secondIsMax() {
  assertEquals(6, max(5, 6));
}

int max(int x, int y) {
	if (y > x)
		return y;
	return x;
}


Now I refactor, in this case to make it comply with the style of my project.

@Test
public void firstIsMax() {
  assertEquals(5, max(5, 4));
}

@Test
public void secondIsMax() {
  assertEquals(6, max(5, 6));
}

int max(int x, int y) {
	if (y > x) {
		return y;
	} else {
		return x;
	}	
}




If code has been written without tests, it can be very difficult to add tests. Getting a code coverage tool to report 70%--80% can be quite challenging as the code is not organised in a way that is conducive to testing.

If the code is written test-first then you only write code in response to a failing test. A coverage tool should report well over 90%. There is a couple of percent leeway because there are often quirks that stop it reporting 100%. For example, in Java, the coverage tool I use can never report 100% for code involving enums or exception handling.

You might find watching some of these informative:
http://www.jamesshor...Blog/Lets-Play/
Was This Post Helpful? 3
  • +
  • -

#3 November-06  Icon User is offline

  • D.I.C Regular

Reputation: 46
  • View blog
  • Posts: 407
  • Joined: 04-January 11

Re: TDD: How to correctly implement?

Posted 21 November 2014 - 03:50 AM

Thanks, cfoley. That's a big help. I was trying this earlier but with the order mixed up. Now it's clearer to me how it's done.

I have also been reading on what to unit test but there is something that is not really clear to me.

According to internet articles, methods with logic, calculations, or any decision-making process should be tested. If getters and setters have logic in them, they should be tested too.

How do you unit test methods with no return value? Also, even if a setter has logic in it, how do you unit test it?

Can you use Assert to unit test methods with no return value?
Was This Post Helpful? 0
  • +
  • -

#4 cfoley  Icon User is offline

  • Cabbage
  • member icon

Reputation: 2069
  • View blog
  • Posts: 4,307
  • Joined: 11-December 07

Re: TDD: How to correctly implement?

Posted 21 November 2014 - 04:24 AM

If a method has no return value then it must have some effect on the world. Test that!

You can check for exceptions (or lack thereof)

@Test
public void zeroIsValidAge() {
	validateAge(0);
	// test passes if no exception is thrown.
}

@Test
public void positiveIsValidAge() {
	validateAge(2);
}

@Test
public void negativeAgeThrowsException() {
	try {
		validateAge(-1);
		fail("Expected exception not thrown.");
	} catch (InvalidAge e) {
		String expectedMessage = "-1 is not a valid age.";
		assertEquals(expectedMessage, e.getMessage());
	}
}

void validateAge(int a) {
	if (a < 0)
		throw new exception(a + " is not a valid age.");
}


You can check that class variables are updated:

@Test
public void setValidAge(3) {
	setAge(3);
	assertEquals(3, getAge());
}

@Test
public void setInvalidValidAgeDoesNotAlterObjectState(3) {
	try {
		setAge(-2);
	} catch (Exception e) {
	}
	assertEquals(0, getAge());
}

@Test
public void setInvalidValidAgeThrowsException(3) {
	try {
		setAge(-2);
		fail();
	} catch (Exception e) {
		String expectedMessage = "-2 is not a valid age.";
		assertEquals(expectedMessage, e.getMessage());
	}
}

private int age = 0;

int getAge() {
	return age;
}

void setAge(int a) {
	validateAge(a);
	age = s;
}

void validateAge(int a) {
	if (a < 0)
		throw new exception(a + " is not a valid age.");
}




What about something more difficult:

void printDetails(Person p) {
	System.out.println("Name is " p.getName() + ", age is " + p.getAge());
}


This is not easily testable, but we can extract parts of it to make them testable:

@Test
public void personDetails() {
	Person p = new Person("Bob", 50);
	assertEquals("Name is Bob, age is 50", makeDetailString(p));
}

String makeDetailString(Person p) {
	return "Name is " p.getName() + ", age is " + p.getAge();
}

void printDetails(Person p) {
	System.out.println(makeDetailString(p));
}



Now the logic is in a method that we can test. There is a small amount left in the printDetais method that is difficult to test. You could decide that it's simple enough to not bother with or you could try and work out how to inject a spy to capture the output. The cost/benefit analysis is up to you.
Was This Post Helpful? 1
  • +
  • -

#5 November-06  Icon User is offline

  • D.I.C Regular

Reputation: 46
  • View blog
  • Posts: 407
  • Joined: 04-January 11

Re: TDD: How to correctly implement?

Posted 21 November 2014 - 05:29 AM

Thanks a lot! That really helps.
Was This Post Helpful? 0
  • +
  • -

#6 November-06  Icon User is offline

  • D.I.C Regular

Reputation: 46
  • View blog
  • Posts: 407
  • Joined: 04-January 11

Re: TDD: How to correctly implement?

Posted 21 November 2014 - 05:37 AM

By the way, how do you test an event? For example, on button click...

private void button1_Click(object sender, EventArgs e)
{
    //Some logic here...
}



Should I place the codes in a method so I can test the method then just have the button call the method? For example...

private void button1_Click(object sender, EventArgs e)
{
    DoSomething();
}

public void DoSomething()
{
    //Some logic here...
}


Was This Post Helpful? 0
  • +
  • -

#7 cfoley  Icon User is offline

  • Cabbage
  • member icon

Reputation: 2069
  • View blog
  • Posts: 4,307
  • Joined: 11-December 07

Re: TDD: How to correctly implement?

Posted 21 November 2014 - 07:51 AM

Quote

Should I place the codes in a method so I can test the method then just have the button call the method? For example...


Yes, that's what I do. It turns out that you often want more than one event listener to do the same thing. For example, pressing enter or clicking a the mouse might do the same thing. Separating your event handling code from your doing stuff code is a good thing to do reguardless of TDD.

Event handlers are just methods. No reason you can't do this:

Object source = someButton;
int id = 0;
String command = "do it!";
ActionEvent e = new ActionEvent(source, it, command);
someListener.actionPerformed(e);


Also no reason you can't do this (although ti will rarely be useful even under TDD)

String[] args = {};
ApplicationLauncher.main(args);

Was This Post Helpful? 0
  • +
  • -

#8 November-06  Icon User is offline

  • D.I.C Regular

Reputation: 46
  • View blog
  • Posts: 407
  • Joined: 04-January 11

Re: TDD: How to correctly implement?

Posted 24 November 2014 - 02:40 AM

Is it possible to unit test a method that accepts no parameter?

public void DoSomething()
{
    if (txt1.Text == "a") then
        //some codes here...
    else
        //some codes here...
}


Was This Post Helpful? 0
  • +
  • -

#9 cfoley  Icon User is offline

  • Cabbage
  • member icon

Reputation: 2069
  • View blog
  • Posts: 4,307
  • Joined: 11-December 07

Re: TDD: How to correctly implement?

Posted 24 November 2014 - 02:47 AM

Your turn. :P Take a guess and tell me what you think.
Was This Post Helpful? 0
  • +
  • -

#10 November-06  Icon User is offline

  • D.I.C Regular

Reputation: 46
  • View blog
  • Posts: 407
  • Joined: 04-January 11

Re: TDD: How to correctly implement?

Posted 24 November 2014 - 03:21 AM

Well, I cannot manipulate the input to test conditions without parameters so may be it cannot be tested.

On the second thought, if it is possible to manipulate the values that will be tested,for example, a method that is reading the values from some global variables, maybe I can manipulate the value of the global variable and have the method generate different outputs.

It's just a thought though. I'm not too sure.
Was This Post Helpful? 0
  • +
  • -

#11 cfoley  Icon User is offline

  • Cabbage
  • member icon

Reputation: 2069
  • View blog
  • Posts: 4,307
  • Joined: 11-December 07

Re: TDD: How to correctly implement?

Posted 24 November 2014 - 04:27 AM

Quote

On the second thought, if it is possible to manipulate the values that will be tested,for example, a method that is reading the values from some global variables, maybe I can manipulate the value of the global variable and have the method generate different outputs.


This is correct!

In a similar vein, there is no return value. But if the method modifies any variables in a wider scope you can assert the values of those afterwards.

An OO program has lots of potential for methods with no parameters or return value. They will often modify the object's instance variables.
Was This Post Helpful? 0
  • +
  • -

#12 November-06  Icon User is offline

  • D.I.C Regular

Reputation: 46
  • View blog
  • Posts: 407
  • Joined: 04-January 11

Re: TDD: How to correctly implement?

Posted 25 November 2014 - 01:49 AM

I am able to complete the simple application I am working on. I am not sure though if I am able to perform enough unit testing. Compared to the many methods that I have in my application, I have only a few methods which I include in my test.

Below are the reasons that I have for not creating a test for a certain method: (Please guide me by telling me if you agree or disagree, and if my reason is valid or invalid)
  • The method does not have any conditions for decision-making
  • The method simply displays something on a label or textbox or any other object
  • The method calls other methods (1 or more)
  • The method has a logical condition but output is displayed in a UI object(textbox/label/MessageBox/etc). (cfoley, should I be using your suggestion for testing methods with no return value here?)
  • The method has a condition but result determines the dynamic addition of a control in the UI
  • The method is returning a random value
  • The condition determines how properties of a control will be set (Enabled, Checked, MaxLength, etc.)

Was This Post Helpful? 0
  • +
  • -

#13 cfoley  Icon User is offline

  • Cabbage
  • member icon

Reputation: 2069
  • View blog
  • Posts: 4,307
  • Joined: 11-December 07

Re: TDD: How to correctly implement?

Posted 25 November 2014 - 02:42 AM

From a dogmatic TDD viewpoint, I disagree with all of them. Not a single line of code should be written unless there is a failing unit test. Only enough code to make the test pass should be written.

Quote

The method does not have any conditions for decision-making


Then it will be very easy to test. No excuse!

Quote

The method simply displays something on a label or textbox or any other object


Easy peasy:

myMehtod();
assertEquals("expected text", textBox.getTest());



Quote

The method calls other methods (1 or more)


Most methods should call one method or more. The trick is knowing what to test. If the helper methods are public, they should be tested independently, so you probably don't have to test all branches from the main method. Remember that you don't write a single line of code without a failing test. That means you at least need some tests that fail if the helper methods are not called. Sometimes you want to test the sequence of the calls, other times you want to be on the lookout for corner cases that arise from the combination of calls.



Quote

The method has a logical condition but output is displayed in a UI object(textbox/label/MessageBox/etc). (cfoley, should I be using your suggestion for testing methods with no return value here?)


Yes, you should be using my suggestion for testing methods with no return values.

Quote

The method has a condition but result determines the dynamic addition of a control in the UI


Then test that the control has been added.

Quote

The method is returning a random value


There are still things to test. You could call it a million times and make sure the random numbers are in the correct range, for example.

Quote

The condition determines how properties of a control will be set (Enabled, Checked, MaxLength, etc.)


assertTrue(control.isEnabled());
assertFalse(control.isChecked());
assertEquals(100, control.maxLength());

Was This Post Helpful? 0
  • +
  • -

#14 cfoley  Icon User is offline

  • Cabbage
  • member icon

Reputation: 2069
  • View blog
  • Posts: 4,307
  • Joined: 11-December 07

Re: TDD: How to correctly implement?

Posted 25 November 2014 - 02:49 AM

I also don't like the distinction you are making between kinds of methods. Methods can have arguments, return values and side effects and you need to test them all. You can make your life easier by having fewer methods with side effects; or try not to mix side effects and return values; or try not to have as many arguments.

From a testing point of view, who cares if there are loops or conditions or try..catch or local variables or anything else. In TDD you write enough tests to define the required functionality and in parallel write enough code to satisfy the tests.

When people say they don't unit test getters and setter, it means they don't have test methods along the lines testGetName(). However, they will be called incidentally from other tests or from other methods (and these other methods will be tested).
Was This Post Helpful? 0
  • +
  • -

#15 November-06  Icon User is offline

  • D.I.C Regular

Reputation: 46
  • View blog
  • Posts: 407
  • Joined: 04-January 11

Re: TDD: How to correctly implement?

Posted 25 November 2014 - 05:36 AM

There are many articles in the internet that discusses which methods to and to not unit test.

I remember reading about not unit testing for methods that generate random numbers. Also, I have read that if you are unit testing a method that calls different methods, then better unit test the methods being called by it. And the more frequent discussed in articles is... "you don't unit test a method with no logic". This includes if...else... statements, switch...case..., loops and other codes that may involve decision-making.

Well, I don't really expect every internet article to be discussing the same thing since they come from different sources and different developers may have different ideas.

But now, I'm confused. It seems that you need to test every method.

Correct me if I am wrong. Here's how I think it works...

If you unit test methods but with the exception of some methods (like what I did), you are unit testing but not using TDD.

If you use TDD, you need to have a test for all methods. In a test first approach, no method will be created without test.

Do I understand it right?

Does this mean that in TDD, there are no exceptions that tells that the method does not need to be tested?

This post has been edited by November-06: 25 November 2014 - 05:49 AM

Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2