A: 

I might be wrong, but I am under the impression that objects/classes should be black boxes to their clients, and so to their testing clients (encapsulating I think is the term I am looking for).

Itay Moav
The effects a method has isn't always directly (or immediately) visible to the client. Also, just because it gave the correct result doesn't mean it did it the right way. Thats why mocks are used - they can tell you if a function or method was called correctly.
Richard Levasseur
hmmm....Playing with the internals of an object to test sounds to me like a good way to introduce more bugs into the system (Eizenberg Eyes Rule).
Itay Moav
Having a method being a blackbox to its test seems to go against TDD. The tests *drive* the design of the method. Mocks not only provide you with a proper mean to isolate your method for testing purposes, but they also ensure that it behaves upon its dependencies as it should.
mike
+1  A: 

These are some good questions... let me first say that I do not really know JS at all, but I am a unit tester and have dealt with these issues. I first want to point out that JsUnit exists if you are not using it.

I wouldn't worry too much about your method calling other methods within the same class... this is bound to happen. What worries me more is the creation of the other object, depending on how complicated it is.

For example, if you are instantiating a class that does all kinds of operations over the network, that is too heavy for a simple unit test. What you would prefer to do is mock out the dependency on that class so that you can have the object produce the result you would expect to receive from its operations on the network, without incurring the overhead of going on the network: network failures, time, etc...

Passing in the other object is a bit messy. What people typically do is have a factory method to instantiate the other object. The factory method can decide, based on whether or not you are testing (typically via a flag) whether or not to instantiate the real object or the mock. In fact, you may want to make the other object a member of you class, and within the constructor, call the factory, or make the decision right there whether or not to instantiate the mock or the real thing. Within the setup function or within your test cases you can set special conditions on the mock object so that it will return the proper value.

Also, just make sure you have tests for your other functions in the same class... I hope this helps!

Tom
The language was php, but it doesn't matter much. I think I understand the strategy of factories inside constructors, but I still worry about public methods in the same class since they can also apply as dependencies and can also encapsulate very involved processes that need mocking.
mike
A: 

There's a few things you can do:

The best thing to do is mock, here's one such library: http://code.google.com/p/php-mock-function

It should let you mock out only the specific functions you want.

If that doesn't work, the next best thing is to provide the implementation of method2 as a method of an object within the MyClass class. I find this one of the easier methods if you can't mock methods directly:

class MyClass {
  function __construct($method2Impl) {
    $this->method2Impl = $method2Impl;
  }
  function method2() {
    return $this->method2Imple->call();
  }
}

Another option is to add an "under test" flag, so that the method behaves different. I don't recommend this either - eventually you'll have differing code paths and with their own bugs.

Another option would be to subclass and override the behaviors you need. I -really- don't suggest this since you'll end up customizing your overridden mock to the point that it'll have bugs itself :).

Finally, if you need to mock out a method because its too complicated, that can be a good sign to move it into its own object and use composition (essentially using the method2Impl technique i mentioned above).

Richard Levasseur
The problem is not so much mocking, but handling of dependencies in general, whether they'd be from other objects or public members of the current object. I want to know if it's acceptable practice to pass a reference to an object to its method for the sake of loose coupling. What's the alternative?
mike
Well, thats certainly not ideal, but no worse than having a flag control behavior.
Richard Levasseur
+1  A: 

Looks like the whole idea of this class is not quite correct. In TDD your are testing classes, but not methods. If a method has it own responsibility and provides it's own (separate testable) functionality it should be moved to a separate class. Otherwise it just breaks the whole OOP encapsulation thing. Particularly it breaks the Single Responsibility Principle.

In your case, I would extract the tested method into another class and injected $var1, $var2, $var3 and $other as dependencies. The $other should be mocked, as well any object which tested class depends on.

class TestMyClass extends MyTestFrameworkUnitTestBase{
     function testMyClass()
     {
          $myClass = new MyClass();
          $myClass->setVar1('asdf');
          $myClass->setVar2(23);
          $myClass->setVar3(78);
          $otherMock = getMockForClassOther();
          $myClass->setOther($otherMock);
          $this->assertEquals('result', $myClass->myMethod());
     }
}

Basic rule I use is: If I want to test something, I should make it a class. This is not always true in PHP though. But it works in PHP in 90% of cases. (Based on my experience)

Max Kosyakov
It does resolve the dependency problem, but am I correct to assume that it also implies that public methods within a class should ideally not interact directly? That is, a public method should preferably only depend on private members of its class (as they aren't tested) and external dependencies.
mike
Well, public method can interact directly. I see no problem in that. But there is a little need for that, when each class has its only responsibility.
Max Kosyakov
A: 

Possibly, this is more a matter of single responsibility principle being violated, which is feeding into TDD issues.

That's a GOOD thing, that means TDD is exposing design flaws. Or so the story goes.

If those methods are not public, and are just you breaking apart you code into more digestable chunks, honestly, I wouldn't care.

If those methods are public, then you've got an issue. Following the rule, 'any public method of a class instance must be callable at any point'. That is to say, if you're requiring some sort of ordering of method calls, then it's time to break that class up.

Saem