所以我在项目中使用laravel并且有一个InvoiceRepository
和一个InvoiceRepositoryTest
,我第一次写了测试。但是我不确定这个测试是否理想,所以我想问一下它是否是一个好的测试或是否需要改进。如果我没有测试该方法的内部工作原理,我有点不确定。
例如$this->model->where('order_id', $order->id)
也可以写成$this->model->whereOrderId($order->id)
,但这样做会完全相同,但会使测试失败。此外,我需要很多Laravel的内部课程才能通过考试。
此Factory
类来自JeffreyWay/Laravel-Test-Helpers package,用于创建填充了一些数据的模型实例。
所以这是存储库中的方法:
public function createUserInvoice(\Order $order)
{
if ($order->status !== 'sent')
{
throw new InvoiceRepositoryException('Cannot create user invoice if the order status is not `sent`');
}
$collection = $this->model->where('order_id', $order->id)
->whereNotNull('user_id')
->get();
if ( ! $collection->isEmpty())
{
throw new InvoiceRepositoryException('Cannot create duplicate user invoice. There already exists a user invoice for the given order');
}
$invoiceData = array(
'order_id' => $order->id,
'user_id' => $order->user_id,
'from_name' => InvoiceRepository::OUR_NAME,
'from_address' => InvoiceRepository::OUR_ADDRESS,
'from_postal_code' => InvoiceRepository::OUR_POSTAL_CODE,
'from_city' => InvoiceRepository::OUR_CITY,
'from_email' => InvoiceRepository::OUR_EMAIL,
'from_vat' => InvoiceRepository::OUR_VAT,
'to_name' => $order->customer_name,
'to_address' => $order->customer_invoice_address,
'to_postal_code' => $order->customer_invoice_postal_code,
'to_city' => $order->customer_invoice_city,
'to_email' => $order->customer_email,
'total' => $order->total
);
$this->model->validateException($invoiceData);
$invoice = $this->model->create($invoiceData);
$invoiceItems = [];
foreach($order->items as $item)
{
$invoiceItems[] = new InvoiceItem(array(
'invoice_id' => $invoice->id,
'description' => $item->product_code ? $item->product_name . ' (' . $item->product_code . ')' : $item->product_name,
'quantity' => $item->quantity,
'price' => $item->price
));
}
$invoice->items()->saveMany($invoiceItems);
return $invoice;
}
这里有3个测试方法和测试用例setUp方法:
public function setUp()
{
parent::setUp();
$this->order = Factory::make('\Order', ['id' => 666]);
$company = Factory::make('\Company', ['id' => 745]);
$company2 = Factory::make('\Company', ['id' => 987]);
// Products must be faked because item has an attribute that depends on it
$product = Factory::make('\Product', ['id' => 12]);
$product2 = Factory::make('\Product', ['id' => 13]);
$product3 = Factory::make('\Product', ['id' => 14]);
$item = Factory::orderItem(array(
'id' => 1,
'order_id' => 666,
'company_id' => 745,
'product_id' => 12,
'subproduct_id' => null,
'product_name' => 'ABC 123',
'product_code' => 'abc123dacode',
'quantity' => 1,
'price' => 98.72
));
$item->company = $company;
$item->product = $product;
$item2 = Factory::orderItem(array(
'id' => 2,
'order_id' => 666,
'company_id' => 745,
'product_id' => 13,
'subproduct_id' => null,
'product_name' => 'Xylofoon Jup',
'quantity' => 3,
'price' => 10.44
));
$item2->company = $company;
$item->product = $product2;
$item3 = Factory::orderItem(array(
'id' => 3,
'order_id' => 666,
'company_id' => 987,
'product_id' => 14,
'subproduct_id' => null,
'product_name' => 'Kleed',
'quantity' => 2,
'price' => 74.50
));
$item->product = $product3;
$item3->company = $company2;
$items = new Collection([$item, $item2, $item3]);
$this->order->items = $items;
$this->invoiceModel = $this->mock('App\Models\Invoice');
$this->invoiceItemModel = $this->mock('App\Models\InvoiceItem');
$this->creditNoteModel = $this->mock('App\Models\CreditNote');
$this->creditNoteItemModel = $this->mock('App\Models\CreditNoteItem');
$this->invoiceRepo = \App::make('App\Repositories\Eloquent\InvoiceRepository');
}
public function testCreateUserInvoice()
{
$this->order->status = 'sent';
$invoiceData = array(
'order_id' => $this->order->id,
'user_id' => $this->order->user_id,
'from_name' => InvoiceRepository::STORESQUARE_NAME,
'from_address' => InvoiceRepository::STORESQUARE_ADDRESS,
'from_postal_code' => InvoiceRepository::STORESQUARE_POSTAL_CODE,
'from_city' => InvoiceRepository::STORESQUARE_CITY,
'from_email' => InvoiceRepository::STORESQUARE_EMAIL,
'from_vat' => InvoiceRepository::STORESQUARE_VAT,
'to_name' => $this->order->customer_name,
'to_address' => $this->order->customer_invoice_address,
'to_postal_code' => $this->order->customer_invoice_postal_code,
'to_city' => $this->order->customer_invoice_city,
'to_email' => $this->order->customer_email,
'total' => $this->order->total
);
$invoice = \Mockery::mock('App\Models\Invoice')->makePartial();
$invoice->fill($invoiceData);
$builder = \Mockery::mock('Illuminate\Database\Eloquent\Builder');
$this->invoiceModel->shouldReceive('where')
->with('order_id', $this->order->id)
->andReturn($builder);
$builder->shouldReceive('whereNotNull')
->with('user_id')
->andReturn($builder);
$builder->shouldReceive('get')
->andReturn(new Collection([]));
$this->invoiceModel->shouldReceive('validateException')
->once()
->with($invoiceData);
$this->invoiceModel->shouldReceive('create')
->once()
->with($invoiceData)
->andReturn($invoice);
$invoiceItems = [];
foreach($this->order->items as $item)
{
$invoiceItems[] = new InvoiceItem(array(
'invoice_id' => $invoice->id,
'description' => $item->product_code ? $item->product_name . ' (' . $item->product_code . ')' : $item->product_name,
'quantity' => $item->quantity,
'price' => $item->price
));
}
$relation = \Mockery::mock('Illuminate\Database\Eloquent\Relations\HasOneOrMany');
$invoice->shouldReceive('items')
->once()
->andReturn($relation);
$relation->shouldReceive('saveMany')
->with($invoiceItems);
$createdInvoice = $this->invoiceRepo->createUserInvoice($this->order);
$this->assertEquals($invoice, $createdInvoice);
}
public function testCreateUserInvoiceInvalidStatusThrowsException()
{
$this->order->status = 'payment_received';
$this->setExpectedException('App\Repositories\Exceptions\InvoiceRepositoryException');
$this->invoiceRepo->createUserInvoice($this->order);
}
public function testCreateUserInvoiceDuplicateThrowsException()
{
$this->order->status = 'sent';
$invoice = Factory::make('App\Models\Invoice', ['id' => 66]);
$builder = \Mockery::mock('Illuminate\Database\Eloquent\Builder');
$this->invoiceModel->shouldReceive('where')
->with('order_id', $this->order->id)
->andReturn($builder);
$builder->shouldReceive('whereNotNull')
->with('user_id')
->andReturn(\Mockery::self())
->shouldReceive('get')
->andReturn(new Collection([$invoice]));
$this->setExpectedException('App\Repositories\Exceptions\InvoiceRepositoryException');
$this->invoiceRepo->createUserInvoice($this->order);
}