-
-
Save JeffreyWay/5674014 to your computer and use it in GitHub Desktop.
<?php | |
class User extends Eloquent { | |
public function getOldest() | |
{ | |
return $this->orderBy('age', 'desc')->first(); | |
} | |
} |
2
2
So here's how you'd basically do it (for #2).
public function testGetsOldestUser()
{
Factory::create('User', ['age' => 20]);
Factory::create('User', ['age' => 30]);
$oldest = (new User)->getOldest();
$this->assertEquals(30, $oldest->age);
}
In general I'd say #1 because this will work (assuming Eloquent works, which we have to) and does not require a test.
I really don't like the idea of 3 (and I've seen you do this quite a bit in some of your testing screencasts recently*) because you're not really testing anything, and you're making the test rely on an implementation detail. The test should test that the method does the right thing, not that it calls a given Eloquent method. But the reasons for not liking this are twofold:
- As I mentioned you're not really testing anything. In this case it's not too bad, but someone with a lower knowldge about unit testing might think this type of testing is acceptable for all tests. Give you a false sense of security about the outcome of the testing.
- Also as I mentioned, you're relying on implementation details of the code when writing the test. What if (god forbid) this code was changed to use the bog standard DB class - the test would now fail even though the code would stil be correct. Similarly, if the ORM was replaced with a different one that didn't use
$this->orderBy()
, all your tests fail - yes, great reminder to change the test code, but now you have to update two lots of code.
Finally, the most real proper answer here is that if you want to test (get full coverage or whatever) the integration test makes the most sense. However, from the comments above it sounds like Laravel do not have a test-database-with-fixtures feature out of the box. That's surprising and a bit of a shame.
*I understand in your tutorials you've been doing a very quick intro to testing so that's fine (although if I were you I'd note during the screencast that normally you'd need to test more or whatever).
@JeffreyWay A-ha I think your 'answer' to #2 answered my question about fixtures (at least to an extent).
Hey, Alex -
I'd always use mocks if the method did more than simply call a method. This is a different case though. Chris outlined my views well.
@JeffreyWay
Mocks is a must when you deal with asynchronous storage. Like RabbitMQ, or web services, for instance. It's really hard to check data there.
If connection happens synchronously, there is no actual reason to separate tests from data. Especially when database is properly cleaned and fixtures are used.
2
2
When dealing with databases and queries, ALWAYS use integration. Yes, you could use a mock expectation that the method was called, and yes, you can have faith that Eloquent will query properly, but with databases, unless you are dealing with real data, you cannot always be absolutely sure that you did it right. What if you typo-d the method or the parameters in the production and test code? Your tests would pass, but you would have a nasty 🐛.
Mocks are much more useful for asserting that interfaces around external APIs are called properly from your own abstraction, not for testing that the ORM runs the right query and the database returns the right values.
Some combination of 2 and 3.
2
2 because we're dealing with datas from the database. Otherwise 3 if you intend to test a method that format a given data.
2 and 3
2
2, using an in-memory database. Good tutorial here: http://code.tutsplus.com/tutorials/testing-like-a-boss-in-laravel-models--net-30087
The integration test should be for Eloquent, but since you're using it more specifically, I'd still do an integration test on this. But, I'd also do a mock for the unit tests. The mock would verify that orderBy is called and give back a mock object. Then you'd also verify that this method is returning the first item in that set.