2014-04-07 14 views
20

Desidero utilizzare un oggetto fittizio (Mockery) nel mio test PHPUnit. L'oggetto mock deve avere sia alcuni metodi pubblici sia alcune proprietà pubbliche impostate. La classe è un modello eloquente di Laravel. Ho provato questo:Mocking di Laravel Modelli eloquenti: come impostare una proprietà pubblica con Mockery

$mock = Mockery::mock('User'); 
$mock->shouldReceive('hasRole')->once()->andReturn(true); //works fine 
$mock->roles = 2; //how to do this? currently returns an error 
$this->assertTrue(someTest($mock)); 

... ma impostando i rendimenti di proprietà pubblica questo errore:

BadMethodCallException: Method Mockery_0_User::setAttribute() does not exist on this mock object

Questo errore non viene restituito quando beffardo una semplice classe, ma viene restituito quando provo a deridere un Modello eloquente Che cosa sto facendo di sbagliato?

+0

Forse una domanda stupida - ma a seconda di ciò che si sta testando si fa nemmeno bisogno di un oggetto fittizio? Se stai testando (per esempio) il metodo hasRole(), perché non usare $ mock = new User; $ mock-> roles = 2; e testarlo? Ad esempio, se sto verificando accessor/presentatori, eccetto solo un oggetto corretto piuttosto che un mock setAttribute, ecc. – Apemantus

+0

@Apemantus ringraziamenti. Sto testando un modello che ha relazioni (un utente ha molti ruoli). Non sono a conoscenza di un modo per impostare le relazioni senza salvare in un database. Sto provando a scrivere un test che non ha bisogno di toccare il database. – mtmacdonald

+0

OK. Non ho testato le nostre relazioni, ma è possibile fare $ mock-> shouldReceive ('setAttribute') -> con ('roles) -> andReturn (2) - ma restituirà solo il numero intero. È possibile restituire una seconda simulazione di un modello di ruolo, se lo si desidera, come in http://stackoverflow.com/questions/20361364/mocking-models-with-a-relationship-in-laravel?rq=1 – Apemantus

risposta

0

Provato questo? Dovrebbe coprire il tuo problema.

https://github.com/padraic/mockery/blob/master/docs/11-MOCKING-PUBLIC-PROPERTIES.md

direi implementare queste

protected $roles = array(); 

public function setRoles($roles) 
{ 
    $this->roles = $roles; 
} 

public function addRole($role) 
{ 
    $this->roles[] = $role; 
} 

Quindi è possibile testare utilizzando:

$mock = Mockery::mock('User'); 
$mock->shouldReceive('hasRole')->once()->andReturn(true); 
$mock->addRole(2); 
$this->assertTrue(someTest($mock)); 

Questo abside ti dà la possibilità di promettere un formato quando si esegue un getRoles() che sarebbe un array di oggetti Role se esegui SOLID OOP, o se preferisci usare array, allora almeno sai che è sempre un array che ottieni.

+3

Sì I leggi questa pagina ma non viene fornito alcun esempio. Quando ho provato set() ottengo ** BadMethodCallException: Method Mockery_0_User :: set() non esiste su questo oggetto fittizio **. Quello che sto davvero cercando è un esempio. – mtmacdonald

+0

Quindi $ mock-> roles = 2 restituisce quale errore? – Oldek

+0

** BadMethodCallException: Metodo Mockery_0_User :: setAttribute() non esiste su questo oggetto fittizio **. – mtmacdonald

0

Hai provato a fare partial mocks? Si può provare qualcosa di simile (non testato):

$mock = Mockery::mock('User[hasRole]'); 
$mock->shouldReceive('hasRole')->once()->andReturn(true); 
$mock->roles = 2; 
$this->assertTrue(someTest($mock)); 
+0

non funziona per il modello Eloquent –

1

Per rispondere alla tua domanda, si potrebbe anche provare qualcosa di simile:

$mock = Mockery::mock('User'); 
$mock->shouldReceive('hasRole')->once()->andReturn(true); //works fine 
$mock->shouldReceive('setAttribute')->passthru(); 
$mock->roles = 2; 

$mock->shouldReceive('getAttribute')->passthru(); 
$this->assertEquals(2, $mock->roles); 

Oppure, come suggerito da seblaze, usare un finto parziale:

$mock = Mockery::mock('User[hasRole]'); 
$mock->shouldReceive('hasRole')->once()->andReturn(true); 
$mock->roles = 2; 
$this->assertEquals(2, $mock->roles); 

Ma, dal snippet di codice, se si sta scrivendo unit test, si dovrebbe davvero fare solo un'affermazione per ogni prova:

function test_someFunctionWhichCallsHasRole_CallsHasRole() { 
    $mock = Mockery::mock('User'); 
    $mock->shouldReceive('hasRole')->once(); 

    $mock->someFunctionWhichCallsHasRole(); 
} 

function test_someFunctionWhichCallsHasRole_hasRoleReturnsTrue_ReturnsTrue() { 
    $mock = Mockery::mock('User'); 
    $mock->shouldReceive('hasRole')->once()->andReturn(true); 

    $result = $mock->someFunctionWhichCallsHasRole(); 

    $this->assertTrue($result); 
}   
11

se si vuole ottenere questa proprietà con questo valore, basta usarlo:

$mock ->shouldReceive('getAttribute') 
    ->with('role') 
    ->andReturn(2); 

Se si chiama $user->role otterrete - 2 ($user - sua classe finta User)

+1

Sto diventando proprietà Undefined: Mockery \ CompositeExpectation :: $ role –

3

Questo la risposta è un po 'in ritardo, ma spero che possa aiutare qualcuno. Attualmente lo si può impostare una proprietà statica su oggetti eloquenti deriso utilizzando la parola chiave 'alias':

$mocked_model = Mockery::mock('alias:Namespace\For\Model'); 
$mocked_model->foo = 'bar'; 
$this->assertEquals('bar', $mocked_model->foo); 

Questo è utile anche per beffardo classi fornitore esterno, come alcuni degli oggetti Stripe.

Leggi di 'alias' e le parole chiave 'sovraccarico': http://docs.mockery.io/en/latest/reference/startup_methods.html

+0

Ricevo l'errore "Impossibile caricare l'app matta \ Modelli \ Utente, la classe esiste già". –

-2

è possibile utilizzare stdClass in questo caso.

$obj = new stdClass(); 
$obj->roles = 2; 
$mock = Mockery::mock('User'); 
// return stdclass here. 
$mock->shouldReceive('hasRole')->once()->andReturn($obj); 
$mock->roles = 2; 
$this->assertEquals(2, $mock->roles); 
+0

No non puoi se il tuo oggetto si aspetta un'istanza di quella classe del modello. – AndrewMcLagan

0

Spy è tuo amico su questo:

$mock = Mockery::spy('User'); 
$mock->shouldReceive('hasRole')->once()->andReturn(true); //works fine 
$mock->roles = 2; //how to do this? currently returns an error 
$this->assertTrue(someTest($mock)); 
Problemi correlati