TDD workshop. Anybody welcome; Data storage abstraction.

Discussion of testing theory and practice, including methodologies (such as TDD, BDD, DDD, Agile, XP) and software - anything to do with testing goes here. (Formerly "The Testing Side of Development")

Moderator: General Moderators

User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: TDD workshop. Anybody welcome; Data storage abstraction.

Post by Christopher »

Chris Corbyn wrote:Why shouldn't the implementing classes handle that? How does the base class know what the child class is doing, what errors it will throw? Why would it care? :) You can still call set_error_handler() from within the enclosing class.
I don't think it was the issue of the base classes knowing what the child classes were doing. The reality is that the main error that occurs here is when trying to open the file. Once the file is open, the error checking is more specific. That's the common functionality. ;)
Chris Corbyn wrote:It may be the case that at some point down the line we do see common functionality and extract a superclass as part of a refactoring. But that's something that comes from refactoring which we'll get to later. We just want the simplest workable solution possible, and right now we don't seem to need a base class :)
I think that is exactly what Jcart ended up doing. But you need to start simple for this demonstration. Hopfully you come up with a brilliant solution. :)
(#10850)
User avatar
arjan.top
Forum Contributor
Posts: 305
Joined: Sun Oct 14, 2007 4:36 am
Location: Hoče, Slovenia

Re: TDD workshop. Anybody welcome; Data storage abstraction.

Post by arjan.top »

Chris Corbyn wrote:Ok, so our interface for the StorageBridge (name sound ok?) is starting to look like this:

Code: Select all

/**
 * A means of reading/writing data to a storage backend.
 */
interface StorageBridge {
  /**
   * Store a value using $key to reference it.
   * @param string $key
   * @param string $value
   */
  public function set($key, $value);
  
  /**
   * Persist changes.
   */
  public function save();
}
"StorageBackend" sounds better actually. Implementing it as XmlBackend, YamlBackend etc.

soooo why is set() in StorageBridge?

Shouldn't be the bridge responsible only for file read/write?

EDIT:
OK we use name StorageModel from now on as decided ...
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Re: TDD workshop. Anybody welcome; Data storage abstraction.

Post by matthijs »

Ok, so we start with something like this

Code: Select all

 
   $store = new DataStore(new XmlModel("/path/to/file.xml"));
   $store->set("/a/know/key", "my value");
   $store->save();
 
But then I don't understand the interface you give. Is that the interface for DataStore or for XmlModel? What are we going to test first. the DataStore or the XMLModel?
User avatar
arjan.top
Forum Contributor
Posts: 305
Joined: Sun Oct 14, 2007 4:36 am
Location: Hoče, Slovenia

Re: TDD workshop. Anybody welcome; Data storage abstraction.

Post by arjan.top »

I would start with StorageModel, then when we have final interface we use mocks on DataStore
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: TDD workshop. Anybody welcome; Data storage abstraction.

Post by Chris Corbyn »

arborint wrote:
Chris Corbyn wrote:Why shouldn't the implementing classes handle that? How does the base class know what the child class is doing, what errors it will throw? Why would it care? :) You can still call set_error_handler() from within the enclosing class.
I don't think it was the issue of the base classes knowing what the child classes were doing. The reality is that the main error that occurs here is when trying to open the file. Once the file is open, the error checking is more specific. That's the common functionality. ;)
But the implementing class can still handle that error provide it's the one opening the file. What if you had a DB config which is all one with SQL to a "config" table or something? Does the base class still expect errors from the file system? I think I'm missing something in your example :) Can you post a longer use case? Actually, not here... I'll run along to the skeleton forum later ;)
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: TDD workshop. Anybody welcome; Data storage abstraction.

Post by Chris Corbyn »

arjan.top wrote:I would start with StorageModel, then when we have final interface we use mocks on DataStore
Yeah, so there's no right/wrong way to go about this. We can use mocks before we ever write each model, or we can write the models first. I agree that we might as well jump into writing one of the Models first. I'd say to start with XML for no other reason than "it's as good a place as any".

It's fairly obvious we need to throw in our get() counterpart to set(). Then we can start testing :)

EDIT | Did those who are taking part up until now download the ZIP from earlier? Are we happy with it?
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: TDD workshop. Anybody welcome; Data storage abstraction.

Post by Chris Corbyn »

matthijs wrote:Ok, so we start with something like this

Code: Select all

 
   $store = new DataStore(new XmlModel("/path/to/file.xml"));
   $store->set("/a/know/key", "my value");
   $store->save();
 
But then I don't understand the interface you give. Is that the interface for DataStore or for XmlModel? What are we going to test first. the DataStore or the XMLModel?
Currently it's looking like both have the same public interface, but the XmlModel acts as an adaptor for DataStore. So any clients only need know about DataStore. We may drop this since we have an interface which represents both... Not sure yet.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: TDD workshop. Anybody welcome; Data storage abstraction.

Post by Christopher »

Chris Corbyn wrote:I think I'm missing something in your example :) Can you post a longer use case? Actually, not here... I'll run along to the skeleton forum later ;)
No need. Continue on here. I think you will improve upon the design and we will learn... :)
(#10850)
User avatar
arjan.top
Forum Contributor
Posts: 305
Joined: Sun Oct 14, 2007 4:36 am
Location: Hoče, Slovenia

Re: TDD workshop. Anybody welcome; Data storage abstraction.

Post by arjan.top »

Chris Corbyn wrote:
arjan.top wrote:I would start with StorageModel, then when we have final interface we use mocks on DataStore
Yeah, so there's no right/wrong way to go about this. We can use mocks before we ever write each model, or we can write the models first. I agree that we might as well jump into writing one of the Models first. I'd say to start with XML for no other reason than "it's as good a place as any".

It's fairly obvious we need to throw in our get() counterpart to set(). Then we can start testing :)

EDIT | Did those who are taking part up until now download the ZIP from earlier? Are we happy with it?
This should have been posted about 8 hours ago (before I went to bed :D ) but devnetwork was offline/working slowly ...

Yes, I downloaded it (and looked it too :) ), I am happy with it :D

And I am still not sure about StorageModel responsibilities (look at post above) ...
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: TDD workshop. Anybody welcome; Data storage abstraction.

Post by Chris Corbyn »

Are you thinking more like DataStore doing all the getting/setting within itself, but then delegating to another component to persist any changes?

Code: Select all

class DataStore {
  get();
  set();
  save();
}
 
interface StorageBridge {
  load();
  save($data);
}
I can go that way too.
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Re: TDD workshop. Anybody welcome; Data storage abstraction.

Post by matthijs »

Ok, is this a start

Code: Select all

 
<?php
require_once dirname(__FILE__) . '/../configure.php';
require_once dirname(__FILE__) . '/../../classes/Datastore.php';
 
class DatastoreTest extends UnitTestCase {
    public function testAddSomethingToDatastore() {
        $data = new DataStore();
        $data->set('foo', 'bar');
        $this->assertEqual($data->get('foo'), 'bar');
    }
}
 
class Datastore {
    public function set(){}
    public function get(){}
}
 
It returns a failing test of course, but I'm not allowed to write any code yet :)
User avatar
arjan.top
Forum Contributor
Posts: 305
Joined: Sun Oct 14, 2007 4:36 am
Location: Hoče, Slovenia

Re: TDD workshop. Anybody welcome; Data storage abstraction.

Post by arjan.top »

Chris Corbyn wrote:Are you thinking more like DataStore doing all the getting/setting within itself, but then delegating to another component to persist any changes?

Code: Select all

class DataStore {
  get();
  set();
  save();
}
 
interface StorageBridge {
  load();
  save($data);
}
I can go that way too.
That's what I had in mind yes, DataStore would store an array of values, Bridge is responsible for converting ...

If that is OK of course :wink:
User avatar
arjan.top
Forum Contributor
Posts: 305
Joined: Sun Oct 14, 2007 4:36 am
Location: Hoče, Slovenia

Re: TDD workshop. Anybody welcome; Data storage abstraction.

Post by arjan.top »

matthijs wrote:Ok, is this a start

Code: Select all

 
<?php
require_once dirname(__FILE__) . '/../configure.php';
require_once dirname(__FILE__) . '/../../classes/Datastore.php';
 
class DatastoreTest extends UnitTestCase {
    public function testAddSomethingToDatastore() {
        $data = new DataStore();
        $data->set('foo', 'bar');
        $this->assertEqual($data->get('foo'), 'bar');
    }
}
 
class Datastore {
    public function set(){}
    public function get(){}
}
 
It returns a failing test of course, but I'm not allowed to write any code yet :)
It won't be OK i think, you are trying to test set and get, none of them is implemented yet
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: TDD workshop. Anybody welcome; Data storage abstraction.

Post by Chris Corbyn »

arjan.top wrote:It won't be OK i think, you are trying to test set and get, none of them is implemented yet
Well, that's sort of the point. It's test-driven so the failing test is our specification for what we have to code. If we're going down the DataStore as a simple container delegating to a persistence layer then what matthijs posted is right.

Let's just establish where we're putting this code first.

In classes/DataStore.php:

Code: Select all

<?php
 
class DataStore {
  public function set($key, $value) {
  }
  public function get($key) {
  }
}
 
In tests/unit/DataStoreTest.php:

Code: Select all

<?php
 
require_once dirname(__FILE__) . '/../configure.php';
require_once dirname(__FILE__) . '/../../classes/DataStore.php';
 
class DataStoreTest extends UnitTestCase {
  public function testAddSometingToDataStore() {
    $data = new DataStore();
    $data->set('foo', 'bar');
    $this->assertEqual($data->get('foo'), 'bar');
  }
}
 
And in tests/AllTests.php:

Code: Select all

<?php
 
require_once dirname(__FILE__) . '/configure.php';
 
class DataStoreTestSuite extends TestSuite {
  public function __construct() {
    parent::__construct('All DataStore tests');
    $this->addFile(TEST_BASE . '/unit/DataStoreTest.php');
  }
}
This produces a failure:

Code: Select all

AllTests.php
1) Equal expectation fails as [NULL] does not match [String: bar] at [/Users/chris/data_store/tests/unit/DataStoreTest.php line 10]
    in testAddSomethingToDataStore
    in DataStoreTest
    in /Users/chris/data_store/tests/unit/DataStoreTest.php
    in All DataStore tests
FAILURES!!!
Test cases run: 1/1, Passes: 0, Failures: 1, Exceptions: 0
Before we continue I'd just like to bring something up. The name of the test method... can we improve it? Is it really describing what we're testing? ;)
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: TDD workshop. Anybody welcome; Data storage abstraction.

Post by Chris Corbyn »

We are missing something though matthijs. We never discussed instantiating the DataStore without a constructor. We have a dependency on StorageModel right? (Sorry, I keep changing its name... can we pick one? :P).
Post Reply