|
Here, I'll provide an example I generated with chatgpt with some prompting. type Server struct {
Payment services.PaymentService
Storage services.StorageService
Quota services.QuotaService
Auth services.AuthService
Notification services.NotificationService
}
// TransactionRequest is the request structure for a purchase
type TransactionRequest struct {
UserID string `json:"user_id"`
AuthToken string `json:"auth_token"`
ProductID string `json:"product_id"`
Price float64 `json:"price"`
Currency string `json:"currency"`
File []byte `json:"file"`
Key string `json:"key"`
}
// TransactionResponse is the response structure after processing a transaction
type TransactionResponse struct {
Status string `json:"status"`
Message string `json:"message"`
}
// HandleTransaction handles the incoming transaction request
func (s *Server) HandleTransaction(w http.ResponseWriter, r *http.Request) {
var req TransactionRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "invalid request", http.StatusBadRequest)
return
}
// Authenticate user
userID, err := s.Auth.Authenticate(req.AuthToken)
if err != nil {
http.Error(w, "authentication failed", http.StatusUnauthorized)
return
}
// Check and update quota
allowed, err := s.Quota.CheckQuota(userID)
if err != nil || !allowed {
http.Error(w, "quota exceeded", http.StatusForbidden)
return
}
s.Quota.UpdateQuota(userID, 1) // Assume updating quota by 1 unit per transaction
// Process payment
transactionID, err := s.Payment.Charge(req.Price, req.Currency, "payment-token")
if err != nil {
http.Error(w, "payment failed", http.StatusInternalServerError)
return
}
// Upload file to S3
fileURL, err := s.Storage.Upload(req.File, userID + "-files", req.Key)
if err != nil {
http.Error(w, "file upload failed", http.StatusInternalServerError)
return
}
// Send notification
notificationMessage := "Your purchase has been processed successfully."
s.Notification.SendNotification(userID, notificationMessage)
response := TransactionResponse{
Status: "success",
Message: "Transaction processed successfully: " + transactionID + " File uploaded to: " + fileURL,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
It is still contrived obviously. But what I would like to show what happens if use stubs. You could pass anything into the dependency parameters and the test would pass. Mock allows you to "lock" in the implementation. Its tightly coupled yes but sometimes that is exactly what you want.In this example that would be the userId, the bucket name, the key. Mock allows you inject faults in the test setup. Lets say I want to test the error handling logic. I could do it with multiple types of stubs but if you squint its starting to look the same. On the topic of Fake vs Stub vs Mock. Real or Fake is the ideal solution here but not always viable due to time/practical constraints. Stubs can be useful but don't give you fine grained control. |
I don't follow. Under no circumstance would the test pass under invalid inputs, be it whether you use mocks, stubs, or even mockery (fakes?).
- Obviously it cannot pass while using mocks – a mock matches the real thing to every last detail. If it will fail while using the real thing, it will fail here as well.
- Obviously it cannot pass while using stubs – a stub matches the real thing, partially, to at least the minimum amount necessary for the sake of testing. If it will fail while using the real thing, it will fail here as well.
- Obviously it cannot pass while using mockery – mockery does not match the real thing in any way, but does require you to specify matching inputs with failure when they don't match. If it will fail while using the real thing, it will fail here as well.
I don't know what you are imagining, but I'm not convinced it is a thing. I mean, you could make it a thing - you can do anything your little heart desires, but there would be no reason to ever make it a thing.
Maybe we need some concrete tests to better illustrate what you are talking about?