So I'm making unit tests using laravel, I have 50 tests. but when a test that requires auth, the test automatically fails and raises a 401 error
Expected status code 404 but received 401. Failed asserting that 404 is identical to 401.
for the failed test, like this is the code. I use actingAs to work around auth, but it always fails
public function testDenyNonAdminUserAccess()
{
$user = factory(User::class)->create();
$author = factory(Author::class)->create();
$response = $this
->actingAs($user)
->postJson('/api/books', [
'isbn' => '9788328302341',
'title' => 'Clean code',
'description' => 'Lorem ipsum',
'authors' => [$author->id],
]);
$response->assertStatus(403);
}
even though when I use postman to insert data, it always works and there are no problems. is there any solution?
I also put the middleware in the controller
public function __construct()
{
$this->middleware(['auth:api', 'auth.admin'])->except('index');
}
is there any solution?
To me, It seems there is no user in your memory database.
Try this one to check whether there are users saved in your DB or not.
User::factory(10)->create();
$this->assertEquals(10, User::get()->count());
If it is, try to login a specific user like this:
$user = User::find(1);
$this->actingAs($user);
Related
For the automated testing of a laravel API I am using the 'laravel' action on github actions, the one made by github actions.
The tests keep failing telling me invalid JSON returned from route, expected response code 200 but got 500, cannot read property status on null and cannot find in json
I'm using laravel sanctum. Could it be a csrf-token problem?
My action yml: https://gist.github.com/I2EJeffrey/77df8faac1b0f86623e2e4449f98d858
My response function:
* success response method.
*
* #return \Illuminate\Http\Response
*/
public function sendResponse($result, $message, $code = 200)
{
$response = [
'success' => true,
'data' => $result, // result is most often one or 2 arrays
'message' => $message,
];
return response()->json($response, 200);
}
Example test:
public function testSuccessfullyCreateAccommodationType()
{
$this->login(); // Login function that lots of tests need.
$response = $this->postJson('/api/v5/accommodations/1/types', ['accommodation_name'=>$this->createName()]);
$response
->assertJsonFragment(['success' => true])
->assertJsonStructure(['success', 'data' =>
[], 'message']); // The array is filled with keys
}
EDIT: 2 errors that I got by using withoutExceptionHandling: https://gist.github.com/I2EJeffrey/da23bfbdf5fba155456bd799a34f6276
EDIT 2: I also get the following warning: TTY mode requires /dev/tty to be read/writable.
EDIT 3: The client model and the client seeder. Whenever I run the tests a mysql docker container starts that gets a db migrated and seeded into it:
https://gist.github.com/I2EJeffrey/39c779df217c9a75a7569f6fa3957d77
https://gist.github.com/I2EJeffrey/41cbbdba8025d38547059d3a6f4d4392
My problem was that the DB didn't get seeded due to not having added $this->call(ClientSeeder::class); to the DatabaseSeeder. Which caused the routes to return null and thus wrong json.
I use Laravel 9, but it is updated version. I mean, the project was written in laravel 5.4 and updated it to 9 later.
Here's my routes
Route::group(['middleware' => 'locale', 'prefix' => '{locale?}'], function () {
Route::get('/signin', 'Front\UsersController#getSignin');
Route::post('/signin', 'Front\UsersController#postSignin');
});
Here's my tests
public function test_get_signin(){
$response = $this->get('/signin');
$response->assertStatus(302);
}
public function test_post_signin(){
$response = $this->post('am/signin');
$response->assertStatus(302);
}
It works well when I do $this->post('am/signin');
But it is not correct. By the idea it must work when I write $this->post('/signin') without manually adding what should be added automatically. But in fact I get status code 405.
UsersController method for post('/signin) route.
public function postSignin($lang, Request $request){
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if (Auth::validate(['email' => $request['email'],'password' => $request['password']])
|| Auth::validate(['username' => $request['email'],'password' => $request['password']])) {
$verify = User::where(['email'=> $request['email']])->first();
$verify = $verify?$verify:User::where(['username'=> $request['email']])->first();
if($verify->status =='blocked'){
if ($request->expectsJson()) {
return response()->json(array('verify'=> trans('email.profile-block')), 422);
}
}elseif(!$verify->verified){
return response()->json(array('verify'=> trans('validation.active_account').' '
.trans('car.click').' <a class="resend-link" href="/'.$lang.'/resendtoken/'.$verify->email_token
.'">'.trans('car.here1').'</a> '.trans('validation.resend_link')), 422);
}elseif($verify->status =='pending'){
return response()->json(array('verify'=> trans('car.company_napp')), 422);
}elseif($verify->status =='active'){
if(filter_var($request->email, FILTER_VALIDATE_EMAIL)){
$field = 'email';
}else{
$field = 'username';
}
if (Auth::attempt([$field => $request->email, 'password'=>$request->password],$request->remember)) {
UserLoginInfo::create(['user_id'=>Auth::id(),'ip_address'=> $request->ip(),
'info'=>json_encode(self::get_user_info())]);
if ($request->remember) {
User::where('id', Auth::id())->update(array('signed_in_for_remember_me' => Carbon::now()));
}
return Auth::user()->balance;
}
}
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
more short:
$this->get('/signin'); gives status code 302
$this->post('am/signin'); gives status code 302
$this->post('/signin'); gives status code 405
I tried
to use withoutMiddleware() - no positive result.
public function test_get_signin(){
$response = $this->withoutMiddleware('locale')->get('/signin');
$response->assertStatus(302);
}
public function test_post_signin(){
$response = $this->withoutMiddleware('locale')->post('/signin');
$response->assertStatus(302);
}
removed "?" symbol from 'prefix' => '{locale?}' in route group - no use.
commented the : Route::get('/signin', 'Front\UsersController#getSignin'); - no use again.
instead of withoutMiddleware('locale') I also used just a withoutMiddleware() - no use again.
IMPORTANT!
Both routes work well when testing with browser. I mean. User can enter his signin page and also successfully be signed in.
What's going on? How can I force post to work automatically with "/signin"? It's also weird, if I manually have to write "am/" then why it returns 302 instead of 200?
Update
I created a new project and tried to experiment there with route group and get, post methods.
Here's the routes
Route::group(['middleware' => 'locale', 'prefix' => '{locale?}'], function () {
Route::get('/test', function () {
return view('welcome');
});
Route::post('/test', function () {
return view('welcome');
});
});
here's the tests
public function test_1()
{
$response = $this->get('/test');
$response->assertStatus(200);
}
public function test_2()
{
$response = $this->post('/test');
$response->assertStatus(200);
}
test1 and test2, both of them return status 404
And when I use tests like this, I mean, adding a prefix manually
public function test_1()
{
$response = $this->get('/am/test');
$response->assertStatus(200);
}
public function test_2()
{
$response = $this->post('/am/test');
$response->assertStatus(200);
}
both of them return 200
This is good, very good. But why in my situation of my current project I get for get method 200 instead of 404 and for post 405 instead of 404, I don't have an idea. The interesting fact. I commented the whole exceptions Handler.php's code and no use. The get method everytime returns 200 when it must return 404.
Update 2
I've got some new interesting info from my experiments. If in my current project I want to test get method with uri "/signin" without '/am' part with $this->withoutMiddleware(); then I get 500, but without $this->withoutMiddleware(); I get 200
And to know what 500 want to say I used $response->dd(); and got this result
Spatie\LaravelIgnition\Exceptions\ViewException: Undefined variable
$errors in file
C:\xampp\htdocs\dashboard\test\hayvcar\storage\framework\views\7ced869fcb986989ef0f5838d6567d1b5fa4f895.php
on line 1
And if use $this->withoutExceptionHandling(); instead of $response->dd();
We'll get this result
Illuminate\View\ViewException : Undefined variable $errors (View: C:\xampp\htdocs\dashboard\test\hayvcar\resources\views\front\transport\index.blade.php)
C:\xampp\htdocs\dashboard\test\hayvcar\storage\framework\views\7ced869fcb986989ef0f5838d6567d1b5fa4f895.php:1
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\Engines\PhpEngine.php:60
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\Engines\CompilerEngine.php:61
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\View.php:139
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\View.php:122
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\View.php:91
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Http\Response.php:69
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Http\Response.php:35
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:833
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:802
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:725
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php:141
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php:116
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:726
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:703
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:667
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:656
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php:167
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php:141
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php:116
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php:142
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php:111
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\MakesHttpRequests.php:526
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\MakesHttpRequests.php:293
C:\xampp\htdocs\dashboard\test\hayvcar\tests\Feature\RoutesTesting.php:1718
Caused by
ErrorException: Undefined variable $errors
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Bootstrap\HandleExceptions.php:255
C:\xampp\htdocs\dashboard\test\hayvcar\storage\framework\views\7ced869fcb986989ef0f5838d6567d1b5fa4f895.php:1
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Filesystem\Filesystem.php:107
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Filesystem\Filesystem.php:108
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\Engines\PhpEngine.php:58
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\Engines\CompilerEngine.php:61
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\View.php:139
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\View.php:122
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\View.php:91
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Http\Response.php:69
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Http\Response.php:35
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:833
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:802
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:725
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php:141
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php:116
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:726
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:703
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:667
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:656
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php:167
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php:141
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php:116
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php:142
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php:111
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\MakesHttpRequests.php:526
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\MakesHttpRequests.php:293
C:\xampp\htdocs\dashboard\test\hayvcar\tests\Feature\RoutesTesting.php:1718
Have you tried delete cached files?
Delete everything in bootstrap\cache and try again on host.
I've explained the whole situation here, for another question, which in this case, it doesn't matter if it's testing or using in browser, when you cache your routes, laravel look for the cached file, instead of defined routes in web.php and api.php.
So if in cached file, you've had route with am/signin then, doesn't matter if you change it to signin or not, in web.php/api.php, it always looking for cached file, which in this case is am/signin.
Temporary questions, answer them by question number :
So you've commented everything in postSignin method, and didn't worked or just a part of it?
You said in browser is working, method is getting $lang from route? because in tests, as far as i can see, you're not passing anything.
Have you tried to change post to patch just for test? (that's because of Patch verb)
You might also try withoutExceptionHandling(); to get more details on error and test output. are you posting full test or just a basic test?
You can add this line to top of your test, $this->withoutExceptionHandling(); and get more details.
Remove $lang from method or just try a new method like below:
public function postSignin(Request $request){
return something or return $this->sendFailedLoginResponse($request); or etc.
}
How did you upgraded your project to Laravel 9? Create a new Laravel project and only test these two routes, get and post.
I am writing tests for my Laravel project. Right now I am testing the authentication code like login, logout, reset password and so on.
Sadly, my test is failing because there is no notification send. I have mocked the notifications but assertSendTo always fails with the reason The expected [Illuminate\Auth\Notifications\ResetPassword] notification was not sent..
However, when actual requesting a reset password email (not in the test, as a normal user on my website) I indeed do get an reset password email. So, it is functional and working but not in my test. How can this be? The .evn is also correct, I have set my mail host to mailtrap.io and I also receive this email... This is the best proof I can give you.
Here is my test:
use App\Models\User;
use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Str;
use Tests\TestCase;
class AuthTest extends TestCase
{
/** #test */
public function a_not_logged_in_user_can_request_a_new_password()
{
Notification::fake();
$email = Str::random() . "#gmail.com";
$current_password = Str::random(16);
$current_password_hash = Hash::make($current_password);
$user = User::factory()->create([
'email' => $email,
'password' => $current_password_hash
]);
$response = $this->json('POST', route('password.email'), ['email' => $email]);
$response->assertStatus(200);
$response->assertLocation(route('home'));
//$this->expectsNotification($user, ResetPassword::class);
Notification::assertSentTo($user, ResetPassword::class);
}
}
Any ideas why the test is not working or whats wrong with it?
Whats also very strange is the fact that the response code 200 is indicating that everything succeeded without any problem.
This is the error I get when executing the test with assertSentTo
1) Tests\Feature\Auth\LoggedIn\ForgotPassword\AuthTest::a_not_logged_in_user_can_request_a_new_password
The expected [Illuminate\Auth\Notifications\ResetPassword] notification was not sent.
Failed asserting that false is true.
MyWebsiteProject/vendor/laravel/framework/src/Illuminate/Support/Testing/Fakes/NotificationFake.php:68
/MyWebsiteProject/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:261
MyWebsiteProject/tests/Feature/Auth/LoggedIn/ForgotPassword/AuthTest.php:35
And this is the error I get when executing it with expectsNotification
1) Tests\Feature\Auth\LoggedIn\ForgotPassword\AuthTest::a_logged_in_user_can_request_a_new_password
The following expected notification were not dispatched: [Illuminate\Auth\Notifications\ResetPassword]
MyWebsiteProject/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php:281
MyWebsiteProject/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:237
MyWebsiteProject/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:153
Kind regards and thank you!
My app was initially created in L5 when the default User.php fully qualified class name was
App\User.php but, according to L8 new pattern, I've duplicated it (to avoid refactoring.... my fault) to App\Models\User.php.
https://twitter.com/taylorotwell/status/1296556354593792000
This partial misalignment, though, left some of my tests behind, expecially the ones involving fake-notifications in which UserFactory kept dispatching (via NotificationFake.php) to App\User.php instead of App\Models\User.php and determining the assertSentTo to fail.
TLDR
make sure that config/auth.php (param providers.users.model) and UserFactory.php rely on the same model.
Expects does just that "expect that something is going to happen", in your case you are expecting it after the fact. The latter is the use case for an assertion. Something like the following is what you need.
class AuthTest extends TestCase
{
/** #test */
public function a_not_logged_in_user_can_request_a_new_password()
{
$email = Str::random() . "#gmail.com";
$current_password = Str::random(16);
$current_password_hash = Hash::make($current_password);
$user = User::factory()->create([
'email' => $email,
'password' => $current_password_hash
]);
// Expect that something is going to happen
$this->expectsNotification($user, ResetPassword::class);
$response = $this->json('POST', route('password.email'), ['email' => $email]);
// Assertion that something has happened
$response->assertStatus(200);
$response->assertLocation(route('home'));
}
}
In case non of the above solutions works for you like in my case, try adding this line at the top of your test function;
$this->withoutExceptionHandling();
This will give you a good error message as to where the problem might be coming from. In my case, I was using the wrong route.
I want to test login method inside the controller, because I am a beginner in writing the tests and because I think that it is wise to test login method. if anyone has any objections let me know. Also I have found many solutions to test the login, but in cakephp 2.
/**
* Log the user into the application
*
* #return void|\Cake\Network\Response
*/
public function login()
{
if ($this->request->is("post")) {
$user = $this->Auth->identify();
if ($user) {
$user = $this->addUsersAssociated($user);
$user = $this->addUserDetailsToSession($user);
$this->Auth->setUser($user);
return $this->redirect($this->Auth->redirectUrl());
}
// User not identified
$this->Flash->error(__d('cockpit', 'Your username or password is incorrect'));
}
}
For example I want to test it when someone comes with wrong and right username/password.
I am a total beginner and I would also like if someone can point me into the right direction (where is the quickest way to learn how to do this). I would like from someone who is independent to learn how to test my code. In other words I don't want to go to official documentation. (Have been there already)
Figure out what happens, respectively what should happen in the different situations, and create tests with proper expectations.
Like on successful login, the user data is being set in the auth storage and a redirect header is being set, that's something you could test. Likewise on a non-successful login attempt, no user data is stored, no redirect header is being set, and a flash message is being rendered.
All these things can easily be checked in a controller integration test using either helper assertion methods, or even manually via the provided session and response objects, check:
$_requestSession
$_response
assertSession()
assertRedirect()
assertRedirectContains()
assertResponse()
assertResponseContains()
etc...
Here's two very basic examples:
namespace App\Test\TestCase\Controller;
use Cake\TestSuite\IntegrationTestCase;
class AccountControllerTest extends IntegrationTestCase
{
public function testLoginOk()
{
$this->enableCsrfToken();
$this->enableSecurityToken();
$this->post('/account/login', [
'username' => 'the-username',
'password' => 'the-password'
]);
$expected = [
'id' => 1,
'username' => 'the-username'
];
$this->assertSession($expected, 'Auth.User');
$expected = [
'controller' => 'Dashboard',
'action' => 'index'
];
$this->assertRedirect($expected);
}
public function testLoginFailure()
{
$this->enableCsrfToken();
$this->enableSecurityToken();
$this->post('/account/login', [
'username' => 'wrong-username',
'password' => 'wrong-password'
]);
$this->assertNull($this->_requestSession->read('Auth.User'));
$this->assertNoRedirect();
$expected = __d('cockpit', 'Your username or password is incorrect');
$this->assertResponseContains($expected);
}
}
See also
Cookbook > Testing > Controller Integration Testing
Cookbook > Testing > Controller Integration Testing > Testing Actions That Require Authentication
Cookbook > Testing > Controller Integration Testing > Assertion methods
I'm having some trouble using Laravel's Input::replace() method to simulate a POST request during unit testing.
According to Jeffrey Way here and here, you can do something like this:
# app/tests/controllers/PostsControllerTest.php
public function testStore()
{
Input::replace($input = ['title' => 'My Title']);</p>
$this->mock
->shouldReceive('create')
->once()
->with($input);
$this->app->instance('Post', $this->mock);
$this->call('POST', 'posts');
$this->assertRedirectedToRoute('posts.index');
}
However, I can't get this to work. Input::all() and all Input::get() calls still return an empty array or null after Input::replace() is used.
This is my test function:
public function test_invalid_login()
{
// Make login attempt with invalid credentials
Input::replace($input = [
'email' => 'bad#email.com',
'password' => 'badpassword',
'remember' => true
]);
$this->mock->shouldReceive('logAttempt')
->once()
->with($input)
->andReturn(false);
$this->action('POST', 'SessionsController#postLogin');
// Should redirect back to login form with old input
$this->assertHasOldInput();
$this->assertRedirectedToAction('SessionsController#getLogin');
}
The $this->mock->shouldReceive() doesn't get called with $input though - it only gets an empty array. I've confirmed this in the debugger by looking at Input::all() and Input::get() for each value, and they're all empty.
TL/DR: How do I send a request with POST data in a Laravel unit test?
You should use Request::replace(), not Input::replace in order to replace input data for the current request.