Unit tests and method visibility

View: New views
11 Messages — Rating Filter:   Alert me  

Unit tests and method visibility

by Francois Suter-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi all,

I'm trying to design my first unit tests (wow!) and I'm faced with a
problem. I want to test the result of a method which should logically be
"protected". But since the test is outside the scope of the class that
method belongs to, I get a fatal error trying to call it.

Is there a way to design unit tests for protected (or private) methods?

Cheers

--

Francois Suter
Cobweb Development Sarl - http://www.cobweb.ch
_______________________________________________
TYPO3-dev mailing list
TYPO3-dev@...
http://lists.netfielders.de/cgi-bin/mailman/listinfo/typo3-dev

Re: Unit tests and method visibility

by Oliver Klee-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

Francois Suter schrieb:
> I'm trying to design my first unit tests (wow!) and I'm faced with a
> problem. I want to test the result of a method which should logically be
> "protected". But since the test is outside the scope of the class that
> method belongs to, I get a fatal error trying to call it.
>
> Is there a way to design unit tests for protected (or private) methods?

Testing private methods is discouraged because they are, well, private
and should not be part of the interface visible to the outside.

For protected methods, you can do this (in two separate files):

class tx_foo_Bar {
  /**
   * Roasts a duck.
   *
   * @return tx_foo_Duck a well-roasted duck
   */
  protected function roastADuck() {
    ...
  }
}

and then in tests/fixtures/:

class tx_foo_TestingBar extends tx_foo_Bar {
  /**
   * Roasts a duck.
   *
   * @return tx_foo_Duck a well-roasted duck
   */
  public function roastADuck() {
    return parent::roastADuck();
  }
}

Then in the Bar test case, you use an instance of TestingBar.


Oliver
_______________________________________________
TYPO3-dev mailing list
TYPO3-dev@...
http://lists.netfielders.de/cgi-bin/mailman/listinfo/typo3-dev

Re: Unit tests and method visibility

by Xavier Perseguers :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Francois,

> I'm trying to design my first unit tests (wow!) and I'm faced with a
> problem. I want to test the result of a method which should logically be
> "protected". But since the test is outside the scope of the class that
> method belongs to, I get a fatal error trying to call it.
>
> Is there a way to design unit tests for protected (or private) methods?

In C# this is done through an accessor. A special dynamically-generated
class that changes your protected methods as public methods for
test-purpose. You test then this class instead of the original one.

But most important is that normally what you want to test is the
signature of your class, meaning the public methods (which in turn will
probably use your protected and private methods, otherwise you wouldn't
have written them).

The inner working of your class is not important as a user but the
public methods should do what they are intended to.

In your case, if you really want to unit-test them, I guess you should
start subclassing your classes with something like this:

class Foo {
     protected function doSomething() {
         // your code
     }
}

// In test files
class SubFoo extends Foo {
     public function exposedDoSomething() {
         return $this->doSomething();
     }
}

--
Xavier Perseguers
http://xavier.perseguers.ch/en

One contribution a day keeps the fork away
_______________________________________________
TYPO3-dev mailing list
TYPO3-dev@...
http://lists.netfielders.de/cgi-bin/mailman/listinfo/typo3-dev

Re: Unit tests and method visibility

by Niels Pardon-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Francois!

One solution would be to create a test-class which extends the class
you're trying to test and declare the protected method within there as
public.

I think I once read that there is a possibility to access private and
protected stuff via Reflection for testing but couldn't find the
information now.

If you want to get some inspiration on unit tests with TYPO3 you may
want to take a look at the extensions oelib and seminars. We gathered
quite a lot experience with unit tests and TYPO3 extensions.

Greets,

Niels


Francois Suter schrieb:

> Hi all,
>
> I'm trying to design my first unit tests (wow!) and I'm faced with a
> problem. I want to test the result of a method which should logically be
> "protected". But since the test is outside the scope of the class that
> method belongs to, I get a fatal error trying to call it.
>
> Is there a way to design unit tests for protected (or private) methods?
>
> Cheers
>
_______________________________________________
TYPO3-dev mailing list
TYPO3-dev@...
http://lists.netfielders.de/cgi-bin/mailman/listinfo/typo3-dev

Re: Unit tests and method visibility

by Niels Pardon-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Nice, 3 people all telling basically the same story :)


Francois Suter schrieb:

> Hi all,
>
> I'm trying to design my first unit tests (wow!) and I'm faced with a
> problem. I want to test the result of a method which should logically be
> "protected". But since the test is outside the scope of the class that
> method belongs to, I get a fatal error trying to call it.
>
> Is there a way to design unit tests for protected (or private) methods?
>
> Cheers
>
_______________________________________________
TYPO3-dev mailing list
TYPO3-dev@...
http://lists.netfielders.de/cgi-bin/mailman/listinfo/typo3-dev

Re: Unit tests and method visibility

by Francois Suter-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

> Nice, 3 people all telling basically the same story :)

Yes :-) Well thanks to all!

I have read in the meantime that protected and private method should not
normally be tested as they represent inner workings of the class. I can
understand this argument, but I don't think that it makes sense in all
cases.

TYPO3 is a collaborative development by a lot of people (core team
members + wider community). It may well happen that someone wants to
optimise code written by someone else. In such a case I'm sure that
person would be happy to find "low level" unit tests to check that even
internal methods are not broken by changes.

A question about the suggestion that the class extends the class to
test: as far as I could see, current TYPO3 core test all extend
tx_phpunit_testcase. Will my test still work if I extend some other
class instead?

Cheers

--

Francois Suter
Cobweb Development Sarl - http://www.cobweb.ch
_______________________________________________
TYPO3-dev mailing list
TYPO3-dev@...
http://lists.netfielders.de/cgi-bin/mailman/listinfo/typo3-dev

Re: Unit tests and method visibility

by Niels Pardon-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Francois!

Francois Suter schrieb:
> A question about the suggestion that the class extends the class to
> test: as far as I could see, current TYPO3 core test all extend
> tx_phpunit_testcase. Will my test still work if I extend some other
> class instead?

I think you got that wrong.

class tx_foo_Bar {
  /**
   * Roasts a duck.
   *
   * @return tx_foo_Duck a well-roasted duck
   */
  protected function roastADuck() {
    ...
  }
}

and then in tests/fixtures/:

class tx_foo_TestingBar extends tx_foo_Bar {
  /**
   * Roasts a duck.
   *
   * @return tx_foo_Duck a well-roasted duck
   */
  public function roastADuck() {
    return parent::roastADuck();
  }
}

Then you create a testcase class in tests/ like this:

class tx_foo_TestingBar_testcase extends tx_phpunit_testcase {
  /**
   * @var tx_foo_TestingBar
   */
  private $fixture;

  public function setUp() {
    $this->fixture = new tx_foo_TestingBar();
  }

  public function tearDown() {
    unset($this->fixture);
  }

  /**
   * @test
   */
  public function roastADuckRoastsADuck() {
    $this->assertEquals(
      roastedDuck,
      $this->fixture->roastADuck()
    );
  }
}
_______________________________________________
TYPO3-dev mailing list
TYPO3-dev@...
http://lists.netfielders.de/cgi-bin/mailman/listinfo/typo3-dev

Re: Unit tests and method visibility

by Francois Suter-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Niels,

> I think you got that wrong.

Indeed I had.

Thanks for clarifying.

--

Francois Suter
Cobweb Development Sarl - http://www.cobweb.ch
_______________________________________________
TYPO3-dev mailing list
TYPO3-dev@...
http://lists.netfielders.de/cgi-bin/mailman/listinfo/typo3-dev

Re: Unit tests and method visibility

by Oliver Klee-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

Francois Suter schrieb:
> TYPO3 is a collaborative development by a lot of people (core team
> members + wider community). It may well happen that someone wants to
> optimise code written by someone else. In such a case I'm sure that
> person would be happy to find "low level" unit tests to check that even
> internal methods are not broken by changes.

This might be a sign that the class is too big and does too much. In
that case, splitting it into smaller classes with high cohesion (ie. the
class has only one purpose) with a well-defined public interface would
be good.

Example: Old-style kickstarter-generated classes are hell to test
because they do everything in one class and have only one necessarily
public method (main). Splitting these classes will greatly improve
maintainability and testability.

So "low-level tests" shouldn't mean "let's test private methods", but
"let's test the lower-level classes instead".


Oliver
_______________________________________________
TYPO3-dev mailing list
TYPO3-dev@...
http://lists.netfielders.de/cgi-bin/mailman/listinfo/typo3-dev

Re: Unit tests and method visibility

by Francois Suter-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

> This might be a sign that the class is too big and does too much. In
> that case, splitting it into smaller classes with high cohesion (ie. the
> class has only one purpose) with a well-defined public interface would
> be good.

That makes sense I guess.

> So "low-level tests" shouldn't mean "let's test private methods", but
> "let's test the lower-level classes instead".

OK, I'll try to keep that in mind.

Cheers

--

Francois Suter
Cobweb Development Sarl - http://www.cobweb.ch
_______________________________________________
TYPO3-dev mailing list
TYPO3-dev@...
http://lists.netfielders.de/cgi-bin/mailman/listinfo/typo3-dev

Re: Unit tests and method visibility

by Bastian Waidelich-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Francois Suter wrote:

Hi Francois,

> I have read in the meantime that protected and private method should not
> normally be tested as they represent inner workings of the class.

That is somewhat true because refactoring will become very costly if you
test too much of the inner workings (as you'd have to adopt lots of test
cases).

You don't want to test _how_ a class works internally, but you want to
make sure it's API behaves as expected.

The problem: With TYPO3 and other frameworks protected methods are
_part_ of the API in most cases and you want to test them too.

Luckily Robert has created a really adjuvant helper and Jochen
backported it to Extbase: buildAccessibleProxy().
See
https://svn.typo3.org/TYPO3v4/CoreProjects/MVC/extbase/trunk/Tests/Base_testcase.php

It allows you to create a proxy object for your class enabling you to
call protected (not private) methods and to set/get protected properties.

Good luck and happy testing
Bastian
_______________________________________________
TYPO3-dev mailing list
TYPO3-dev@...
http://lists.netfielders.de/cgi-bin/mailman/listinfo/typo3-dev