TDD workshop. Anybody welcome; Data storage abstraction.
Moderator: General Moderators
- 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.
Here's the latest files (including above test) by the way. Sorry, should have posted them before.
- Attachments
-
- data_store.zip
- (136.92 KiB) Downloaded 187 times
Re: TDD workshop. Anybody welcome; Data storage abstraction.
test for multidimensional array:
Code: Select all
public function testSavingMultipleValuesPassesMultidimensionalArray() {
$storageModel = $this->_createStorageModel();
$storageModel->expectOnce('save', array( array(
'foo' => array(
'bar' => array(
'zip' => 'button'
)
),
'foo2' => array(
'bar2' => 'button2'
)
)
));
$dataStore = $this->_createDataStore($storageModel);
$dataStore->set('foo/bar/zip', 'button');
$dataStore->set('foo2/bar2', 'button2');
$dataStore->save();
}
Re: TDD workshop. Anybody welcome; Data storage abstraction.
Sorry, this confuses me only more. First, how does save() accept an array if it doesn't have any function parameters?Chris Corbyn wrote: Definitely worth further explanation. We all need to be clear what we're doing. In my opinion, save() should accept an array in exactly the same format as the array provided by load(). When that array is modified (by set() or remove()) the array passed to save() should reflect that modification.
We don't care what happens to the internal array ($this->_store) when set() or remove() are called. We don't even care that such an internal array exists. What we do care about is that save() receives integral data.
Second, why don't we care about the internal array?
I thought that:
- instantiating the DataStore will load the StorageModel.
- now the private $_store is the array of data having been loaded
- by calling set($var,$value) or remove($key) we manipulate that $_store array.
- calling save() put that array $_store back in the StorageModel.
- 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.
Still passes. Looking good 
Test for load() followed by save().
Test for load() followed by save().
Code: Select all
public function testSavingUnmodifedData() {
$storageModel = $this->_createStorageModel();
$storageModel->setReturnValue('load', array('foo' => 'bar'));
$storageModel->expectOnce('save', array( array('foo' => 'bar') );
$dataStore = $this->_createDataStore($storageModel);
$dataStore->save();
}Re: TDD workshop. Anybody welcome; Data storage abstraction.
save does have $data parameter:
EDIT:
I see now, we are testing StorageModel save() not DataStore save()
EDIT2:
wrong, we are not testing save() we are just testing parameters of save basically ...
Code: Select all
interface StorageModel {
public function save($data);
public function load();
}
EDIT:
I see now, we are testing StorageModel save() not DataStore save()
EDIT2:
wrong, we are not testing save() we are just testing parameters of save basically ...
Re: TDD workshop. Anybody welcome; Data storage abstraction.
now it would pass
(bracket missing)
Chris | Thanks, spotted then when a ran the test 
Code: Select all
public function testSavingUnmodifedData() {
$storageModel = $this->_createStorageModel();
$storageModel->setReturnValue('load', array('foo' => 'bar'));
$storageModel->expectOnce('save', array( array('foo' => 'bar')) );
$dataStore = $this->_createDataStore($storageModel);
$dataStore->save();
}
- 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.
StorageModel->save() has a parameter. DataStore->save() doesn't thoughmatthijs wrote:Sorry, this confuses me only more. First, how does save() accept an array if it doesn't have any function parameters?
Because it's not part of the public API. Setting and getting values we care about. We care that values go into and back out correctly. What *is* part of the public API is $storageModel->save() though. We're about to to start testing load() and save() on a real StorageModel soon so we need to know that DataStore is doing the same thing our tests will be doing.matthijs wrote:Second, why don't we care about the internal array?
Correct. We care that it asks the StorageModel for its data. But we don't care what it does with it. It could stick it in a database for all we care. It could use a comma delimited string. It could use a little object known only to itself. We don't care. We just care that the interfaces we've written are being used correctly- instantiating the DataStore will load the StorageModel.
In our implementation yes. This has nothing to do with the behaviour of our class from an outside point of view though.- now the private $_store is the array of data having been loaded
Again, in our implementation yes.- by calling set($var,$value) or remove($key) we manipulate that $_store array.
In our implementation yes. But the only bit we care about on the public side of things is that $storageModel is given data in a known format. Since we've written an interface for StorageModel we have specified a way to extend the DataStore. A developer needs to know that a StorageModel he implements will be given a multidimensional array. So as a result, we need to test that this is indeed the case. if we had no test to show that's what our code does then how can somebody write a StorageModel implementation?- calling save() put that array $_store back in the StorageModel.
Re: TDD workshop. Anybody welcome; Data storage abstraction.
Ok, you guys lost me.
I'll reread some of the posts and try to get it.
I'll reread some of the posts and try to get it.
- 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.
I get the feeling it may be that you're getting mixed up with the difference between DataStore and StorageModel?matthijs wrote:Ok, you guys lost me.
I'll reread some of the posts and try to get it.
In terms of the whole debate about not caring about $_store. Just look at it this way. All we care about are the methods we declare as "public function ...".
Re: TDD workshop. Anybody welcome; Data storage abstraction.
But we are still testing datastore right? Not storagemodel? And the datastore class doesn't have an argument in the save() method. I thought that calling
$datastore->save() just takes the current state of $_store and saves that to the storagemodel.
$datastore->save() just takes the current state of $_store and saves that to the storagemodel.
- 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.
Correct. But DataStore passes an argument to StorageModel. It would be all well and good to ignore this fact and just write tests for StorageModel later on, passing in "ideal" values for the sake of testing, but we need to know that DataStore is also passing in ideal values.matthijs wrote:But we are still testing datastore right? Not storagemodel?
Bingo! You basically just described what we need to test, and what we have just written the last two tests forAnd the datastore class doesn't have an argument in the save() method. I thought that calling
$datastore->save() just takes the current state of $_store and saves that to the storagemodel.
$storageModel is a mock object in our test case. Mock objects are able to make expectations about arguments which get passed to their methods. As you describe in the above quote "$datastore->save() just takes the current state of $_store and saves that to the storagemodel". Does it? Let's test it to make sure then
Re: TDD workshop. Anybody welcome; Data storage abstraction.
Ok, so as we can't test what is in $_store (it's private), we test if what is in $datastore->save and what is been sent to $storage_model->save is correct.
I think I get it. I was being confused by the talk about arguments for save().
I think I get it. I was being confused by the talk about arguments for save().
- 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.
Correctmatthijs wrote:Ok, so as we can't test what is in $_store (it's private), we test if what is in $datastore->save and what is been sent to $storage_model->save is correct.
I think I get it. I was being confused by the talk about arguments for save().
I really want people to understand why though
Imagine when we create our XmlStorageModel and we want it to generate some XML. It will have to be called something like this:
Code: Select all
$xml = new XmlStorageModel('/some/xml/file.xml');
$xml->save(array('foo' => 'bar'));Unrelated to this discussion, I fear I'm about to confuse people even more, since the next thing we're going to test is that specification we had regarding being able to read data in one format and write it in another
Re: TDD workshop. Anybody welcome; Data storage abstraction.
Ok, but with the 3 tests so far
What is still missing then? Should we feed load() a completely different format?
This is getting more difficult then I'd have thought. But maybe it's good to use the few brain cells that are left once in a while..
Code: Select all
public function testSavingSingleValuePassesSimpleArray() {
$storageModel = $this->_createStorageModel();
$storageModel->expectOnce('save', array( array('zip' => 'button') ));
$dataStore = $this->_createDataStore($storageModel);
$dataStore->set('zip', 'button');
$dataStore->save();
}
public function testSavingMultipleValuesPassesMultidimensionalArray() {
$storageModel = $this->_createStorageModel();
$storageModel->expectOnce('save', array( array(
'foo' => array(
'bar' => array(
'zip' => 'button'
)
),
'foo2' => array(
'bar2' => 'button2'
)
)
));
$dataStore = $this->_createDataStore($storageModel);
$dataStore->set('foo/bar/zip', 'button');
$dataStore->set('foo2/bar2', 'button2');
$dataStore->save();
}
public function testSavingUnmodifedData() {
$storageModel = $this->_createStorageModel();
$storageModel->setReturnValue('load', array('foo' => 'bar'));
$storageModel->expectOnce('save', array( array('foo' => 'bar')) );
$dataStore = $this->_createDataStore($storageModel);
$dataStore->save();
}
This is getting more difficult then I'd have thought. But maybe it's good to use the few brain cells that are left once in a while..
- 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.
Nope, let's not touch load(). It's working fine
save() is working fine too as our previous tests just showed 
But just to add some confusion how I envisaged saving in a different format was like this:
Now I *have* added a paramater to DataStore->save(), but that's for this special case. It will be an optional parameter which simply allow the data to be saved in a different model. Imagine if our concrete models were XmlModel and YamlModel then we could do:
So rather than saving to the XML file, we can direct the persistent data elsewhere.
This is a point for us to think about. Is this interface logical? Can we think of any better alternatives?
But just to add some confusion how I envisaged saving in a different format was like this:
Code: Select all
$dataStore = new DataStore($modelA);
$dataStore->save($modelB);Code: Select all
$dataStore = new DataStore(new XmlModel('file.xml'));
$dataStore->set('whatever', 'xyz');
$dataStore->save(new YamlModel('file.yml'));This is a point for us to think about. Is this interface logical? Can we think of any better alternatives?