GitHub
Tests: 12 • Commercial: 2 • Pet projects: 4 • Legacy: 4
Total: 22

.NET Framework

Test
2021

Project Request

ASP.NET MVC • C# • SQL Server
Idea of the project: if someone wants to order a project development, here you can send an application.
Test
2020

ProjectC

ASP.NET MVC • C# • JSON • jQuery
JSON data processing.
Test
2020

Vehicle Maintenance

ASP.NET MVC • VB.NET • JSON
Idea of the project: if someone wants to order a project development, here you can send an application.
Test
2019

Movie Navigator

ASP.NET MVC • VB.NET
Request information about movie from IMDB.
Test
2018

Customers Exchange

ASP.NET MVC • C# • SQL Server
Automated teller machine emulation.
Test
2016

ATM

ASP.NET MVC • C#
Automated teller machine emulation.

.NET Core

Pet project
2022

Mail Daemon

.NET 8 • Console • JSON
Utility to send mails with customizable settings.

Custom

Code
2024

Buns of code

.NET Framework • C# • JavaScript
Code snippets from my projects, ready to use; tiny tests; code examples.

PHP

Test
2024

Mediabox

PHP 8 • Laravel 11 • Vue.js • Composer • SQLite
Test project for media files management.
Test
2020

Loan Castle

PHP • MariaDB
Jums jāizstrādā kāda lielāk projekta prototips. Izstrādājot prototipu, paturiet prātā, ka projektam attīstoties, šo prototipu varētu vajadzēt pilnveidot.
Test
2020

Content Management

PHP • MySQL • AJAX
Создать простой сайт, где будет страница с формой для авторизации и страница для авторизованного пользователя.
Test
2019

Laravel

PHP • Laravel • Vue.js • Composer • SQLite
Izveidot aplikāciju, kura ik pēc noteikta intervāla (60 sekundes) veic ierakstu datubāzē izmantojot Laravel freimworka iebūvēto funkcionalitāti.
Test
2019

Phone Check

PHP • JavaScript • JSON • Docker
Implement application to detect country by phone number.

Frontend

Test
2021

Forex Wall

npm • React
For this exercise, what we need is a simple live wall for tracking currencies.

Business projects

Commercial
2008

Certification Center

.NET Framework 4.8 • ASP.NET Web Forms • C# • LINQ • SQL Server • ADO.NET • Dapper • JavaScript • jQuery • Git
Transport registration and certification services in Latvia, Customer Relationship Management.
Commercial
2000

Amerikas Auto

.NET Framework 4.8 • ASP.NET Web Forms • C# • LINQ • SQL Server • ADO.NET • Entity Framework • JavaScript • jQuery • Git
Car service and spare parts for all USA and European car models, Customer Relationship Management.

Pet projects

Pet project
2023

Geolocation Assistant

.NET 8 • ASP.NET Core • C# • Web API • JSON • Git
Website for determining geolocation by IP or geotagged photo.
Pet project
2008

Web Dynamics

.NET Framework 4.8 • ASP.NET Web Forms • C# • LINQ • Web API • JSON • SQL Server • Dapper • JavaScript • jQuery • SVG • Git
Software development blog. Articles, books, videos, content management.
Pet project
2000

Blackball

.NET Framework 4.8 • ASP.NET Web Forms • C# • LINQ • Web API • JSON • XML • SQL Server • Dapper • JavaScript • jQuery • SVG • Git
My entertainment portal created from scratch.

Good old times

Legacy
2000

DOS Clock

Turbo Pascal • Assembler
Digital clock.
Legacy
2000

BrainOut

Turbo Pascal • Assembler
Tank battle game.
Legacy
1999

Airport Administrator

Turbo Pascal
Курсовая работа в институте.
Legacy
1998

Atomizer

Turbo Pascal • Assembler
Atomizer, aka «Studio2D». Graphic raster editor. AGI is my own «Atomizer Generated Image» file format.

Laravel

2019 Test

Izveidot aplikāciju, kura ik pēc noteikta intervāla (60 sekundes) veic ierakstu datubāzē izmantojot Laravel freimworka iebūvēto funkcionalitāti.

PHP Laravel Vue.js Composer SQLite
Information
Source code
  app
  Http
  Auth
  css
  js
  js
  lang
  en
  sass
  app
  data
  logs
  Unit
  src
  src
  lib
  docs
  en
  src
  docs
  en
  lib
  src
  Cron
  Cron
  src
  filp
  src
  css
  js
  Util
  src
  ORM
  Spot
  test
  Core
  Text
  Type
  Xml
  Core
  Text
  Type
  Xml
  html
  src
  src
  src
  Auth
  make
  auth
  Bus
  Auth
  Bus
  Http
  Mail
  View
  Auth
  Bus
  Http
  Http
  Json
  Log
  Mail
  html
  text
  Jobs
  View
  src
  src
  Util
  docs
  Pass
  Pass
  Pass
  doc
  src
  Curl
  doc
  f001
  f002
  f003
  f004
  f005
  f006
  f007
  f008
  src
  Date
  Spl
  src
  Lang
  List
  doc
  lib
  Node
  Expr
  Cast
  Name
  Stmt
  test
  code
  expr
  uvs
  stmt
  loop
  expr
  stmt
  Node
  Stmt
  src
  opis
  src
  dist
  lib
  src
  xml
  xml
  src
  Unit
  src
  src
  Tags
  src
  src
  src
  Call
  Node
  Call
  Util
  src
  Node
  Html
  css
  js
  Xml
  HTML
  XML
  src
  src
  src
  src
  src
  Stub
  Hook
  Util
  Log
  PHP
  cli
  1149
  1216
  1265
  1330
  1335
  1337
  1348
  1351
  1374
  1437
  1468
  1471
  1472
  1570
  2085
  2137
  2145
  2158
  2366
  2380
  2382
  2435
  244
  2448
  2724
  2725
  2731
  2811
  2830
  2972
  3093
  3107
  3156
  322
  3364
  3379
  3380
  3396
  433
  445
  498
  503
  581
  74
  765
  797
  873
  Trac
  1021
  523
  578
  684
  783
  fail
  unit
  Util
  PHP
  psr
  src
  log
  Psr
  Log
  Test
  src
  psy
  src
  Sudo
  Util
  test
  Sudo
  Util
  box
  uuid
  src
  Time
  Node
  Time
  src
  src
  diff
  src
  out
  src
  src
  src
  src
  src
  src
  src
  src
  doc
  lib
  Mime
  Pop
  Auth
  Mime
  bug
  unit
  Mime
  Auth
  dkim
  Node
  Node
  psr4
  phpt
  .dot
  b
  a
  A
  B
  C
  copy
  A
  B
  C
  one
  b
  .dot
  a
  dir
  File
  Test
  File
  test
  Test
  Log
  Log
  mime
  Part
  test
  Part
  glob
  Test
  data
  dat
  res
  Util
  Util
  Test
  css
  js
  Test
  Test
  src
  src
  Css
  Rule
  src
  src
  .env
  null
Root / vendor / phpspec / prophecy
Name
Size
Date created
Date modified
src
27.07.2024 15:15
27.07.2024 15:15
8 KB
03.07.2019 02:18
03.07.2019 02:18
1 KB
03.07.2019 02:18
03.07.2019 02:18
1 KB
03.07.2019 02:18
03.07.2019 02:18
14 KB
03.07.2019 02:18
03.07.2019 02:18
README.MD

Prophecy

Stable release Build Status

Prophecy is a highly opinionated yet very powerful and flexible PHP object mocking framework. Though initially it was created to fulfil phpspec2 needs, it is flexible enough to be used inside any testing framework out there with minimal effort.

A simple example

<?php

class UserTest extends PHPUnit_Framework_TestCase
{
    private $prophet;

    public function testPasswordHashing()
    {
        $hasher = $this->prophet->prophesize('App\Security\Hasher');
        $user   = new App\Entity\User($hasher->reveal());

        $hasher->generateHash($user, 'qwerty')->willReturn('hashed_pass');

        $user->setPassword('qwerty');

        $this->assertEquals('hashed_pass', $user->getPassword());
    }

    protected function setup()
    {
        $this->prophet = new \Prophecy\Prophet;
    }

    protected function tearDown()
    {
        $this->prophet->checkPredictions();
    }
}

Installation

Prerequisites

Prophecy requires PHP 5.3.3 or greater.

Setup through composer

First, add Prophecy to the list of dependencies inside your composer.json:

{
    "require-dev": {
        "phpspec/prophecy": "~1.0"
    }
}

Then simply install it with composer:

$> composer install --prefer-dist

You can read more about Composer on its official webpage.

How to use it

First of all, in Prophecy every word has a logical meaning, even the name of the library itself (Prophecy). When you start feeling that, you'll become very fluid with this tool.

For example, Prophecy has been named that way because it concentrates on describing the future behavior of objects with very limited knowledge about them. But as with any other prophecy, those object prophecies can't create themselves - there should be a Prophet:

$prophet = new Prophecy\Prophet;

The Prophet creates prophecies by prophesizing them:

$prophecy = $prophet->prophesize();

The result of the prophesize() method call is a new object of class ObjectProphecy. Yes, that's your specific object prophecy, which describes how your object would behave in the near future. But first, you need to specify which object you're talking about, right?

$prophecy->willExtend('stdClass');
$prophecy->willImplement('SessionHandlerInterface');

There are 2 interesting calls - willExtend and willImplement. The first one tells object prophecy that our object should extend specific class, the second one says that it should implement some interface. Obviously, objects in PHP can implement multiple interfaces, but extend only one parent class.

Dummies

Ok, now we have our object prophecy. What can we do with it? First of all, we can get our object dummy by revealing its prophecy:

$dummy = $prophecy->reveal();

The $dummy variable now holds a special dummy object. Dummy objects are objects that extend and/or implement preset classes/interfaces by overriding all their public methods. The key point about dummies is that they do not hold any logic - they just do nothing. Any method of the dummy will always return null and the dummy will never throw any exceptions. Dummy is your friend if you don't care about the actual behavior of this double and just need a token object to satisfy a method typehint.

You need to understand one thing - a dummy is not a prophecy. Your object prophecy is still assigned to $prophecy variable and in order to manipulate with your expectations, you should work with it. $dummy is a dummy - a simple php object that tries to fulfil your prophecy.

Stubs

Ok, now we know how to create basic prophecies and reveal dummies from them. That's awesome if we don't care about our doubles (objects that reflect originals) interactions. If we do, we need to use stubs or mocks.

A stub is an object double, which doesn't have any expectations about the object behavior, but when put in specific environment, behaves in specific way. Ok, I know, it's cryptic, but bear with me for a minute. Simply put, a stub is a dummy, which depending on the called method signature does different things (has logic). To create stubs in Prophecy:

$prophecy->read('123')->willReturn('value');

Oh wow. We've just made an arbitrary call on the object prophecy? Yes, we did. And this call returned us a new object instance of class MethodProphecy. Yep, that's a specific method with arguments prophecy. Method prophecies give you the ability to create method promises or predictions. We'll talk about method predictions later in the Mocks section.

Promises

Promises are logical blocks, that represent your fictional methods in prophecy terms and they are handled by the MethodProphecy::will(PromiseInterface $promise) method. As a matter of fact, the call that we made earlier (willReturn('value')) is a simple shortcut to:

$prophecy->read('123')->will(new Prophecy\Promise\ReturnPromise(array('value')));

This promise will cause any call to our double's read() method with exactly one argument - '123' to always return 'value'. But that's only for this promise, there's plenty others you can use:

  • ReturnPromise or ->willReturn(1) - returns a value from a method call
  • ReturnArgumentPromise or ->willReturnArgument($index) - returns the nth method argument from call
  • ThrowPromise or ->willThrow($exception) - causes the method to throw specific exception
  • CallbackPromise or ->will($callback) - gives you a quick way to define your own custom logic

Keep in mind, that you can always add even more promises by implementing Prophecy\Promise\PromiseInterface.

Method prophecies idempotency

Prophecy enforces same method prophecies and, as a consequence, same promises and predictions for the same method calls with the same arguments. This means:

$methodProphecy1 = $prophecy->read('123');
$methodProphecy2 = $prophecy->read('123');
$methodProphecy3 = $prophecy->read('321');

$methodProphecy1 === $methodProphecy2;
$methodProphecy1 !== $methodProphecy3;

That's interesting, right? Now you might ask me how would you define more complex behaviors where some method call changes behavior of others. In PHPUnit or Mockery you do that by predicting how many times your method will be called. In Prophecy, you'll use promises for that:

$user->getName()->willReturn(null);

// For PHP 5.4
$user->setName('everzet')->will(function () {
    $this->getName()->willReturn('everzet');
});

// For PHP 5.3
$user->setName('everzet')->will(function ($args, $user) {
    $user->getName()->willReturn('everzet');
});

// Or
$user->setName('everzet')->will(function ($args) use ($user) {
    $user->getName()->willReturn('everzet');
});

And now it doesn't matter how many times or in which order your methods are called. What matters is their behaviors and how well you faked it.

Arguments wildcarding

The previous example is awesome (at least I hope it is for you), but that's not optimal enough. We hardcoded 'everzet' in our expectation. Isn't there a better way? In fact there is, but it involves understanding what this 'everzet' actually is.

You see, even if method arguments used during method prophecy creation look like simple method arguments, in reality they are not. They are argument token wildcards. As a matter of fact, ->setName('everzet') looks like a simple call just because Prophecy automatically transforms it under the hood into:

$user->setName(new Prophecy\Argument\Token\ExactValueToken('everzet'));

Those argument tokens are simple PHP classes, that implement Prophecy\Argument\Token\TokenInterface and tell Prophecy how to compare real arguments with your expectations. And yes, those classnames are damn big. That's why there's a shortcut class Prophecy\Argument, which you can use to create tokens like that:

use Prophecy\Argument;

$user->setName(Argument::exact('everzet'));

ExactValueToken is not very useful in our case as it forced us to hardcode the username. That's why Prophecy comes bundled with a bunch of other tokens:

  • IdenticalValueToken or Argument::is($value) - checks that the argument is identical to a specific value
  • ExactValueToken or Argument::exact($value) - checks that the argument matches a specific value
  • TypeToken or Argument::type($typeOrClass) - checks that the argument matches a specific type or classname
  • ObjectStateToken or Argument::which($method, $value) - checks that the argument method returns a specific value
  • CallbackToken or Argument::that(callback) - checks that the argument matches a custom callback
  • AnyValueToken or Argument::any() - matches any argument
  • AnyValuesToken or Argument::cetera() - matches any arguments to the rest of the signature
  • StringContainsToken or Argument::containingString($value) - checks that the argument contains a specific string value

And you can add even more by implementing TokenInterface with your own custom classes.

So, let's refactor our initial {set,get}Name() logic with argument tokens:

use Prophecy\Argument;

$user->getName()->willReturn(null);

// For PHP 5.4
$user->setName(Argument::type('string'))->will(function ($args) {
    $this->getName()->willReturn($args[0]);
});

// For PHP 5.3
$user->setName(Argument::type('string'))->will(function ($args, $user) {
    $user->getName()->willReturn($args[0]);
});

// Or
$user->setName(Argument::type('string'))->will(function ($args) use ($user) {
    $user->getName()->willReturn($args[0]);
});

That's it. Now our {set,get}Name() prophecy will work with any string argument provided to it. We've just described how our stub object should behave, even though the original object could have no behavior whatsoever.

One last bit about arguments now. You might ask, what happens in case of:

use Prophecy\Argument;

$user->getName()->willReturn(null);

// For PHP 5.4
$user->setName(Argument::type('string'))->will(function ($args) {
    $this->getName()->willReturn($args[0]);
});

// For PHP 5.3
$user->setName(Argument::type('string'))->will(function ($args, $user) {
    $user->getName()->willReturn($args[0]);
});

// Or
$user->setName(Argument::type('string'))->will(function ($args) use ($user) {
    $user->getName()->willReturn($args[0]);
});

$user->setName(Argument::any())->will(function () {
});

Nothing. Your stub will continue behaving the way it did before. That's because of how arguments wildcarding works. Every argument token type has a different score level, which wildcard then uses to calculate the final arguments match score and use the method prophecy promise that has the highest score. In this case, Argument::type() in case of success scores 5 and Argument::any() scores 3. So the type token wins, as does the first setName() method prophecy and its promise. The simple rule of thumb - more precise token always wins.

Getting stub objects

Ok, now we know how to define our prophecy method promises, let's get our stub from it:

$stub = $prophecy->reveal();

As you might see, the only difference between how we get dummies and stubs is that with stubs we describe every object conversation instead of just agreeing with null returns (object being dummy). As a matter of fact, after you define your first promise (method call), Prophecy will force you to define all the communications - it throws the UnexpectedCallException for any call you didn't describe with object prophecy before calling it on a stub.

Mocks

Now we know how to define doubles without behavior (dummies) and doubles with behavior, but no expectations (stubs). What's left is doubles for which we have some expectations. These are called mocks and in Prophecy they look almost exactly the same as stubs, except that they define predictions instead of promises on method prophecies:

$entityManager->flush()->shouldBeCalled();

Predictions

The shouldBeCalled() method here assigns CallPrediction to our method prophecy. Predictions are a delayed behavior check for your prophecies. You see, during the entire lifetime of your doubles, Prophecy records every single call you're making against it inside your code. After that, Prophecy can use this collected information to check if it matches defined predictions. You can assign predictions to method prophecies using the MethodProphecy::should(PredictionInterface $prediction) method. As a matter of fact, the shouldBeCalled() method we used earlier is just a shortcut to:

$entityManager->flush()->should(new Prophecy\Prediction\CallPrediction());

It checks if your method of interest (that matches both the method name and the arguments wildcard) was called 1 or more times. If the prediction failed then it throws an exception. When does this check happen? Whenever you call checkPredictions() on the main Prophet object:

$prophet->checkPredictions();

In PHPUnit, you would want to put this call into the tearDown() method. If no predictions are defined, it would do nothing. So it won't harm to call it after every test.

There are plenty more predictions you can play with:

  • CallPrediction or shouldBeCalled() - checks that the method has been called 1 or more times
  • NoCallsPrediction or shouldNotBeCalled() - checks that the method has not been called
  • CallTimesPrediction or shouldBeCalledTimes($count) - checks that the method has been called $count times
  • CallbackPrediction or should($callback) - checks the method against your own custom callback

Of course, you can always create your own custom prediction any time by implementing PredictionInterface.

Spies

The last bit of awesomeness in Prophecy is out-of-the-box spies support. As I said in the previous section, Prophecy records every call made during the double's entire lifetime. This means you don't need to record predictions in order to check them. You can also do it manually by using the MethodProphecy::shouldHave(PredictionInterface $prediction) method:

$em = $prophet->prophesize('Doctrine\ORM\EntityManager');

$controller->createUser($em->reveal());

$em->flush()->shouldHaveBeenCalled();

Such manipulation with doubles is called spying. And with Prophecy it just works.