It turns out to be zero because (a) the future method is not called until Test.stopTest(), and (b) immediately after Test.stopTest(), you go back in to the test's governor limits. In addition to Adrian's suggestion, you could also have a "universal" method that does the actual callout and provides a nice hook for consistent monitoring:
public class ...
Typically, if I want to verify the callout is made and there may be asynchronous processing involve, I just track it on my mock.
class MyMock implements HttpCalloutMock
Integer calls = 0;
public HttpResponse respond(HttpRequest request)
// mock implementation here
Then, in your test, you just cache your mock ...
You're pretty close to a solution with your parent-child subquery.
The big thing to realize is that, similar to how adding parent__r.someField__c gives you a real SObject instance nested in your query results, a parent-child subquery gives you a List<SObject> nested in your query results.
About the only thing I'd add is to limit the subquery rows to ...
You can use a HAVING clause:
AggregateResult results = [SELECT COUNT(Id) sum, Tool__c Id FROM Gear__c WHERE Tool__c = :tools GROUP BY Tool__c HAVING COUNT(Id) > 1];
This will give you a list of AggregateResult objects where the sum and Tool__c Id are given. You can even use the Map trick to get the count per record easily: