Laravel测试:这个测试是否过多了内部工作?

时间:2014-10-27 20:31:20

标签: unit-testing laravel mockery

所以我在项目中使用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);
}

0 个答案:

没有答案