Re: TDD workshop. Anybody welcome; Data storage abstraction.
Posted: Sun Apr 27, 2008 5:45 am
Here's the latest files (including above test) by the way. Sorry, should have posted them before.
A community of PHP developers offering assistance, advice, discussion, and friendship.
http://forums.devnetwork.net/
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();
}
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.
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();
}Code: Select all
interface StorageModel {
public function save($data);
public function load();
}
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();
}
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.
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.
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.
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().
Code: Select all
$xml = new XmlStorageModel('/some/xml/file.xml');
$xml->save(array('foo' => 'bar'));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();
}
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'));