diff --git a/.gitignore b/.gitignore
index ccef0560f5e81eb78c47d43c0464ed4e04ee6434..42e837a184d13a9f374155ec15ba7c8f14e64cae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
 /vendor/
-.idea
\ No newline at end of file
+.idea
+composer.lock
+build-coverage
\ No newline at end of file
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 97023aa7cc1943a9985c3f2b6e9842974fe72759..6e2af39c768c3e0f5a783a227fe0238499d91a60 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,56 +1,16 @@
 variables:
-  WPDESK_CI_VERSION: 1.10.19
-  MYSQL_ROOT_PASSWORD: mysql
-  MYSQL_DATABASE: wptest
-  MYSQL_USER: mysql
-  MYSQL_PASSWORD: mysql
-  MYSQL_INNODB_LOG_BUFFER_SIZE: 32M
   PHP_ERROR_REPORTING: E_ALL
   COMPOSER_ALLOW_SUPERUSER: 1
   GIT_STRATEGY: fetch
-  ACCEPTANCE_ERROR_PATH: ${CI_PROJECT_DIR}/acceptance
 
 stages:
   - tools
   - tests
-  - pre-deploy
-  - deploy
 
 .template: &job-test-template
   stage: tests
   coverage: '/^\s*Lines:\s*\d+.\d+\%/'
 
-.template: &job-test-integration-template
-  <<: *job-test-template
-  services:
-    - mysql:5.6
-  script:
-    - echo ${WPDESK_CI_VERSION}
-    - ls -l
-    - php --version
-    - cat /tmp/wordpress-develop/src/wp-includes/version.php
-    - cat /tmp/woocommerce/woocommerce.php
-    - composer update --no-progress
-    - if [[ -f tests/integration/prepare.sh ]]; then sh tests/integration/prepare.sh; fi
-    - vendor/bin/phpunit --configuration phpunit-integration.xml --coverage-text --colors=never
-  only:
-    - tags
-
-.template: &job-test-integration-template-fast
-  <<: *job-test-integration-template
-  script:
-    - echo ${WPDESK_CI_VERSION}
-    - ls -l
-    - php --version
-    - cat /tmp/wordpress-develop/src/wp-includes/version.php
-    - cat /tmp/woocommerce/woocommerce.php
-    - composer update --no-progress
-    - if [[ -f tests/integration/prepare.sh ]]; then sh tests/integration/prepare.sh; fi
-    - vendor/bin/phpunit --configuration phpunit-integration.xml --no-coverage
-  except:
-    - tags
-  only:
-
 .template: &job-test-unit-template
   <<: *job-test-template
   script:
@@ -61,8 +21,6 @@ stages:
     - cat /tmp/woocommerce/woocommerce.php
     - composer update --no-progress
     - vendor/bin/phpunit --configuration phpunit-unit.xml --coverage-text --colors=never
-  only:
-    - tags
 
 .template: &job-test-unit-template-fast
   <<: *job-test-unit-template
@@ -74,21 +32,7 @@ stages:
     - cat /tmp/woocommerce/woocommerce.php
     - composer update --no-progress
     - vendor/bin/phpunit --configuration phpunit-unit.xml --no-coverage
-  except:
-    - tags
-  only:
 
-.template: &job-deploy-template
-  image: wpdesknet/amazon-svn-deploy
-  stage: deploy
-  dependencies:
-    - build to deploy
-    - unit test lastest coverage
-    - integration test lastest coverage
-  retry: 2
-  when: manual
-  only:
-    - tags
 
 before_script:
   - cd ${CI_PROJECT_DIR}
@@ -121,190 +65,10 @@ churn metrics:
     - composer update --no-progress
     - vendor/bin/churn run classes inc
 
-#code style test:
-# stage: tests
-#  image: wpdesknet/phpunit-woocommerce:0-0
-#  allow_failure: true
-#  script:
-#    - echo ${WPDESK_CI_VERSION}
-#    - composer update --no-progress
-#    - vendor/bin/phpcs
-
 unit test lastest:
   <<: *job-test-unit-template-fast
   image: wpdesknet/phpunit-woocommerce:0-0
 
 integration test lastest:
-  <<: *job-test-integration-template-fast
-  image: wpdesknet/phpunit-woocommerce:0-0
-
-unit test lastest coverage:
   <<: *job-test-unit-template
   image: wpdesknet/phpunit-woocommerce:0-0
-
-integration test lastest coverage:
-  <<: *job-test-integration-template
-  image: wpdesknet/phpunit-woocommerce:0-0
-
-integration test php7-1 wc-1:
-  <<: *job-test-integration-template-fast
-  image: wpdesknet/phpunit-woocommerce:1-1
-
-integration test php7 wc-2:
-  <<: *job-test-integration-template-fast
-  image: wpdesknet/phpunit-woocommerce:2-2
-
-integration test php-7 wc-3:
-  <<: *job-test-integration-template-fast
-  image: wpdesknet/phpunit-woocommerce:2-3
-
-integration test php5-6:
-  <<: *job-test-integration-template-fast
-  image: wpdesknet/phpunit-woocommerce:3-0
-
-integration test php5-5:
-  <<: *job-test-integration-template-fast
-  image: wpdesknet/phpunit-woocommerce:4-0
-
-integration test current woocommerce:
-  <<: *job-test-integration-template-fast
-  image: wpdesknet/phpunit-woocommerce:0-0
-  allow_failure: true
-  before_script:
-    - cd /tmp
-    - rm -rf woocommerce
-    - git clone https://github.com/woocommerce/woocommerce.git
-    - cd ${CI_PROJECT_DIR}
-
-acceptance test:
-  image: wpdesknet/node
-  variables:
-    CI_DEBUG_SERVICES: trace
-  services:
-    - name: mysql:5.6
-      alias: mysqltests
-    - name: wpdesknet/apache-woocommerce:latest
-      alias: wootests
-    - name: selenium/standalone-chrome
-      alias: selenium
-  artifacts:
-    when: always
-    expire_in: 1 day
-    name: "error logs"
-    paths:
-      - ${CI_PROJECT_DIR}/acceptance
-  stage: tests
-  allow_failure: true
-  script:
-    - cd ${CI_PROJECT_DIR}
-    - composer update --no-progress --no-dev
-    - if [[ -f ${CI_PROJECT_DIR}/tests/acceptance/prepare.sh ]]; then sh ${CI_PROJECT_DIR}/tests/acceptance/prepare.sh; fi
-
-    - export MYSQL_IP=$(awk '/^[[:space:]]*($|#)/{next} /mysqltests/{print $1; exit}' /etc/hosts)
-    - export WOOTESTS_IP=$(awk '/^[[:space:]]*($|#)/{next} /wootests/{print $1; exit}' /etc/hosts)
-    - echo "http://wootests/wpdesk_init.php?mysql_ip=${MYSQL_IP}&wootests_ip=${WOOTESTS_IP}"
-    - wget -O /tmp/wpdesk_init.txt "http://wootests/wpdesk_init.php?mysql_ip=${MYSQL_IP}&wootests_ip=${WOOTESTS_IP}"
-    - tail -50 /tmp/wpdesk_init.txt
-
-    - sh /tmp/clone.sh git@gitlab.com:wpdesk/plugins-tests.git /tmp/tests headless
-    - cd /tmp/tests
-    - npm install
-    - npm install -g grunt-cli
-    - cd node_modules/.bin
-    - ./webdriver-manager update
-    - cd ../
-    - mkdir -p ${CI_PROJECT_DIR}/acceptance/reports/html/screenshot
-    - grunt chrome-${CI_PROJECT_NAME}
-
-
-apigen docs:
-  image:
-    name: wpdesknet/apigen
-  stage: pre-deploy
-  artifacts:
-    expire_in: 1 day
-    name: "docs"
-    paths:
-      - docs/
-  script:
-    - echo ${WPDESK_CI_VERSION}
-    - ls -l
-    - /app/vendor/bin/apigen generate
-    - php /app/hooks-docs.php ${CI_PROJECT_DIR}
-  only:
-    - tags
-
-pages:
-  stage: deploy
-  dependencies:
-    - apigen docs
-  script:
-    - rm -rf public
-    - mv docs/ public/
-    - 'curl -X POST --data-urlencode "payload={\"text\": \"Dokumentacja projektu ${CI_PROJECT_NAME} w wersji ${CI_COMMIT_REF_NAME} umieszczona w <https://gitlab.com/wpdesk/${CI_PROJECT_NAME}/pages|pages> \", }" https://hooks.slack.com/services/${SLACK_AUTH}'
-  artifacts:
-    expire_in: 1 day
-    paths:
-      - public
-  only:
-    - tags
-
-build to deploy:
-  image: wpdesknet/phpunit-woocommerce:4-0
-  stage: pre-deploy
-  artifacts:
-    expire_in: 1 month
-    name: "production release"
-    paths:
-      - release
-      - release.zip
-  script:
-    - echo ${WPDESK_CI_VERSION}
-    - php --version
-    - ls -l
-    - /tmp/set_version.sh ${CI_COMMIT_REF_NAME}
-    - rm -rf ${CI_PROJECT_DIR}/release ${CI_PROJECT_DIR}/release.zip /tmp/release
-    - mkdir /tmp/release
-    - mkdir -p ${CI_PROJECT_DIR}/release/${CI_PROJECT_NAME}
-    - cp -rf ${CI_PROJECT_DIR}/* /tmp/release
-    - cp -rf /tmp/release/* ${CI_PROJECT_DIR}/release/${CI_PROJECT_NAME}
-    - cd ${CI_PROJECT_DIR}/release/${CI_PROJECT_NAME}
-    - composer install --no-dev --no-progress --optimize-autoloader
-    - rm -rf build-coverage release tests docs .git .editorconfig .gitignore .gitlab-ci.yml apigen.neon phpunit.xml acceptance test_soap.php .gitlab
-    - rm -rf composer.json composer.lock phpcs.xml.dist phpunit-integration.xml phpunit-unit.xml composer.phar wp-cli.phar
-    - cd ../
-    - zip -r -q ../release.zip ./
-  only:
-    - tags
-
-deploy to shop:
-  <<: *job-deploy-template
-  script:
-    - echo ${WPDESK_CI_VERSION}
-    - /tmp/deploy_shop.sh ${CI_PROJECT_NAME} release.zip ${CI_PROJECT_NAME}.zip
-    - 'curl -X POST --data-urlencode "payload={\"text\": \"Projekt <https://gitlab.com/wpdesk/${CI_PROJECT_NAME}|${CI_PROJECT_NAME}> zdeployowany do sklepu w wersji ${CI_COMMIT_REF_NAME}\", }" https://hooks.slack.com/services/${SLACK_AUTH}'
-  environment:
-    name: wpdesk shop
-    url: https://wpdeskplugin.s3.amazonaws.com/${CI_PROJECT_NAME}.zip
-
-deploy to demo:
-  <<: *job-deploy-template
-  script:
-    - echo ${WPDESK_CI_VERSION}
-    - /tmp/deploy_demo.sh release/${CI_PROJECT_NAME} ${CI_PROJECT_NAME}
-    - 'curl -X POST --data-urlencode "payload={\"text\": \"Projekt <https://gitlab.com/wpdesk/${CI_PROJECT_NAME}|${CI_PROJECT_NAME}> zdeployowany do demo w wersji ${CI_COMMIT_REF_NAME}\", }" https://hooks.slack.com/services/${SLACK_AUTH}'
-  environment:
-    name: wpdesk demo
-    url: https://demo.wpdesk.org
-
-deploy to repository:
-  <<: *job-deploy-template
-  script:
-    - echo ${WPDESK_CI_VERSION}
-    - rm -rf /tmp/svn-repository
-    - mkdir /tmp/svn-repository
-    - /tmp/deploy_repository.sh ${CI_PROJECT_NAME} ${CI_PROJECT_DIR}/release/${CI_PROJECT_NAME} /tmp/svn-repository
-    - 'curl -X POST --data-urlencode "payload={\"text\": \"Projekt <https://gitlab.com/wpdesk/${CI_PROJECT_NAME}|${CI_PROJECT_NAME}> zdeployowany do repozytorium WP w wersji ${CI_COMMIT_REF_NAME}\", }" https://hooks.slack.com/services/${SLACK_AUTH}'
-  environment:
-    name: wordpress repository
-    url: https://downloads.wordpress.org/plugin/${CI_PROJECT_NAME}.${CI_COMMIT_REF_NAME}.zip
diff --git a/phpunit-integration.xml b/phpunit-integration.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c4a8e8535177a8a9ffdf768b4272d479bc47a8ca
--- /dev/null
+++ b/phpunit-integration.xml
@@ -0,0 +1,28 @@
+<phpunit bootstrap="tests/integration/bootstrap.php"
+         backupGlobals="false"
+     >
+    <testsuites>
+        <testsuite>
+            <directory prefix="Test" suffix=".php">./tests/integration</directory>
+        </testsuite>
+    </testsuites>
+
+    <filter>
+        <whitelist>
+            <directory suffix=".php">classes</directory>
+        </whitelist>
+    </filter>
+
+    <logging>
+        <log type="junit" target="build-coverage/report.junit.xml"/>
+        <log type="coverage-html" target="build-coverage/coverage" charset="UTF-8" yui="true" highlight="true"/>
+        <log type="coverage-text" target="build-coverage/coverage.txt"/>
+        <log type="coverage-clover" target="build-coverage/clover.xml"/>
+    </logging>
+
+    <php>
+        <env name="WP_DEVELOP_DIR" value="/tmp/wordpress-develop"/>
+        <env name="WC_DEVELOP_DIR" value="/tmp/woocommerce"/>
+    </php>
+
+</phpunit>
\ No newline at end of file
diff --git a/phpunit-unit.xml b/phpunit-unit.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e22f6be926377957fc342499bdf481ef6314c611
--- /dev/null
+++ b/phpunit-unit.xml
@@ -0,0 +1,21 @@
+<phpunit bootstrap="tests/unit/bootstrap.php">
+    <testsuites>
+        <testsuite>
+            <directory prefix="Test" suffix=".php">./tests/unit/</directory>
+        </testsuite>
+    </testsuites>
+
+    <filter>
+        <whitelist>
+            <directory suffix=".php">classes</directory>
+        </whitelist>
+    </filter>
+
+    <logging>
+        <log type="junit" target="build-coverage/report.junit.xml"/>
+        <log type="coverage-html" target="build-coverage/coverage" charset="UTF-8" yui="true" highlight="true"/>
+        <log type="coverage-text" target="build-coverage/coverage.txt"/>
+        <log type="coverage-clover" target="build-coverage/clover.xml"/>
+    </logging>
+
+</phpunit>
diff --git a/src/Renderer/Renderer.php b/src/Renderer/Renderer.php
index 230e7649086442932f80d9ce36afb5badec8c146..35aecc42293b9aba64859fd40badebbcbb9f6e2c 100644
--- a/src/Renderer/Renderer.php
+++ b/src/Renderer/Renderer.php
@@ -7,21 +7,20 @@ use WPDesk\View\Resolver\Resolver;
 /**
  * Can render templates
  */
-interface Renderer {
-	/**
-	 * Set the resolver used to map a template name to a resource the renderer may consume.
-	 *
-	 * @param  Resolver $resolver
-	 *
-	 * @return Resolver
-	 */
-	public function set_resolver( Resolver $resolver );
+interface Renderer
+{
+    /**
+     * Set the resolver used to map a template name to a resource the renderer may consume.
+     *
+     * @param  Resolver $resolver
+     */
+    public function set_resolver(Resolver $resolver);
 
-	/**
-	 * @param string $template
-	 * @param array $params
-	 *
-	 * @return string
-	 */
-	public function render( $template, $params );
+    /**
+     * @param string $template
+     * @param array $params
+     *
+     * @return string
+     */
+    public function render($template, array $params = null);
 }
diff --git a/src/Renderer/SimplePhpRenderer.php b/src/Renderer/SimplePhpRenderer.php
new file mode 100644
index 0000000000000000000000000000000000000000..9d05084e69624437d6015c02f780885a4b225a00
--- /dev/null
+++ b/src/Renderer/SimplePhpRenderer.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace WPDesk\View\Renderer;
+
+use WPDesk\View\Resolver\Resolver;
+
+/**
+ * Can render templates
+ */
+class SimplePhpRenderer implements Renderer
+{
+    /** @var Resolver */
+    private $resolver;
+
+    public function __construct(Resolver $resolver)
+    {
+        $this->set_resolver($resolver);
+    }
+
+    /**
+     * @param Resolver $resolver
+     *
+     * @return void|Resolver
+     */
+    public function set_resolver(Resolver $resolver)
+    {
+        $this->resolver = $resolver;
+    }
+
+    /**
+     * @param string $template
+     * @param array|null $params
+     *
+     * @return string
+     */
+    public function render($template, array $params = null)
+    {
+        if ($params !== null) {
+            extract($params, EXTR_SKIP);
+        }
+
+        ob_start();
+        include($this->resolver->resolve($template . '.php'));
+
+        return ob_get_clean();
+    }
+
+}
diff --git a/src/Resolver/ChainResolver.php b/src/Resolver/ChainResolver.php
new file mode 100644
index 0000000000000000000000000000000000000000..eaa394f1d761aa032fa3da442540bbfdeadb20a3
--- /dev/null
+++ b/src/Resolver/ChainResolver.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace WPDesk\View\Resolver;
+
+
+use WPDesk\View\Renderer\Renderer;
+use WPDesk\View\Resolver\Exception\CanNotResolve;
+
+/**
+ * Provide resolvers and this class can try them one after another
+ *
+ * @package WPDesk\View\Resolver
+ */
+class ChainResolver implements Resolver
+{
+    /** @var Resolver[] */
+    private $resolvers;
+
+    /**
+     * Warning: function with variadic input. Input should be list of Resolver instances.
+     */
+    public function __construct()
+    {
+        $args = func_get_args();
+        foreach ($args as $resolver) {
+            $this->appendResolver($resolver);
+        }
+    }
+
+    /**
+     * Append resolver to the end of the list
+     *
+     * @param Resolver $resolver
+     */
+    public function appendResolver( $resolver)
+    {
+        $this->resolvers[] = $resolver;
+    }
+
+    /**
+     * Resolve name to full path
+     *
+     * @param string $name
+     * @param Renderer|null $renderer
+     *
+     * @return string
+     */
+    public function resolve($name, Renderer $renderer = null)
+    {
+        foreach ($this->resolvers as $resolver) {
+            try {
+                return $resolver->resolve($name);
+            } catch (CanNotResolve $e) {
+                // not interested
+            }
+        }
+
+        throw new CanNotResolve("Cannot resolve {$name}");
+    }
+
+}
diff --git a/src/Resolver/DirResolver.php b/src/Resolver/DirResolver.php
new file mode 100644
index 0000000000000000000000000000000000000000..69f1b6cca966ae5b396327152baf40d690ed48df
--- /dev/null
+++ b/src/Resolver/DirResolver.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace WPDesk\View\Resolver;
+
+
+use WPDesk\View\Renderer\Renderer;
+use WPDesk\View\Resolver\Exception\CanNotResolve;
+
+/**
+ * Class should resolve name by serching in provided dir. If empty then current dir
+ *
+ * @package WPDesk\View\Resolver
+ */
+class DirResolver implements Resolver
+{
+
+    /** @var string */
+    private $dir;
+
+
+    /**
+     * Base path for templates ie. subdir
+     *
+     * @param $dir
+     */
+    public function __construct($dir)
+    {
+        $this->dir = $dir;
+    }
+
+    /**
+     * Resolve name to full path
+     *
+     * @param string $name
+     * @param Renderer|null $renderer
+     *
+     * @return string
+     */
+    public function resolve($name, Renderer $renderer = null)
+    {
+        $dir = rtrim($this->dir, '/');
+        $fullName = $dir . '/' . $name;
+        if (file_exists($fullName)) {
+            return $fullName;
+        }
+
+        throw new CanNotResolve("Cannot resolve {$name}");
+    }
+
+}
diff --git a/src/Resolver/Exception/CanNotResolve.php b/src/Resolver/Exception/CanNotResolve.php
new file mode 100644
index 0000000000000000000000000000000000000000..c52dc7c7d6caad8e85d95bbd97f971d25042a7fd
--- /dev/null
+++ b/src/Resolver/Exception/CanNotResolve.php
@@ -0,0 +1,10 @@
+<?php
+
+
+namespace WPDesk\View\Resolver\Exception;
+
+
+class CanNotResolve extends \RuntimeException
+{
+
+}
\ No newline at end of file
diff --git a/src/Resolver/NullResolver.php b/src/Resolver/NullResolver.php
new file mode 100644
index 0000000000000000000000000000000000000000..4f69832fb4944bb87ecc7f1706ea3dd1c8790ece
--- /dev/null
+++ b/src/Resolver/NullResolver.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace WPDesk\View\Resolver;
+
+
+use WPDesk\View\Renderer\Renderer;
+use WPDesk\View\Resolver\Exception\CanNotResolve;
+
+/**
+ * This resolver never finds the file
+ *
+ * @package WPDesk\View\Resolver
+ */
+class NullResolver implements Resolver
+{
+
+    public function resolve($name, Renderer $renderer = null)
+    {
+        throw new CanNotResolve("Null Cannot resolve");
+    }
+
+}
diff --git a/src/Resolver/Resolver.php b/src/Resolver/Resolver.php
index 74c56bab73156fbd249b889dc8133b038b0f6ce9..ac5095964bb115941c72f089f35b0fa5acf9c3c6 100644
--- a/src/Resolver/Resolver.php
+++ b/src/Resolver/Resolver.php
@@ -14,7 +14,7 @@ interface Resolver {
 	 * @param  string $name
 	 * @param  null|Resolver $renderer
 	 *
-	 * @return mixed
+	 * @return string
 	 */
 	public function resolve($name, Renderer $renderer = null);
 }
diff --git a/src/Resolver/WPThemeResolver.php b/src/Resolver/WPThemeResolver.php
new file mode 100644
index 0000000000000000000000000000000000000000..d95028ca24e72f3f63717c6a1f01d03a27116110
--- /dev/null
+++ b/src/Resolver/WPThemeResolver.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace WPDesk\View\Resolver;
+
+
+use WPDesk\View\Renderer\Renderer;
+use WPDesk\View\Resolver\Exception\CanNotResolve;
+
+/**
+ * Class should resolve name by standard wp theme resolve
+ *
+ * @package WPDesk\View\Resolver
+ */
+class WPThemeResolver implements Resolver
+{
+
+    /** @var string */
+    private $template_base_path;
+
+
+    /**
+     * Base path for templates ie. subdir
+     *
+     * @param $template_base_path
+     */
+    public function __construct($template_base_path)
+    {
+        $this->template_base_path = $template_base_path;
+    }
+
+    /**
+     * Resolve name to full path
+     *
+     * @param string $name
+     * @param Renderer|null $renderer
+     *
+     * @return string
+     */
+    public function resolve($name, Renderer $renderer = null)
+    {
+        $templateFile = locate_template(
+            [
+                trailingslashit($this->template_base_path) . $name,
+            ]
+        );
+        if ( ! $templateFile) {
+            throw new CanNotResolve("Cannot resolve {$name}");
+        }
+
+        return $templateFile;
+    }
+
+}
diff --git a/tests/integration/bootstrap.php b/tests/integration/bootstrap.php
new file mode 100644
index 0000000000000000000000000000000000000000..a422fd9c7fea652a15b2aced0b2e6134a5590201
--- /dev/null
+++ b/tests/integration/bootstrap.php
@@ -0,0 +1,28 @@
+<?php
+
+ini_set('error_reporting', E_ALL); // or error_reporting(E_ALL);
+ini_set('display_errors', '1');
+ini_set('display_startup_errors', '1');
+
+require_once __DIR__ . '/../../vendor/autoload.php';
+
+// disable xdebug backtrace
+if ( function_exists( 'xdebug_disable' ) ) {
+	xdebug_disable();
+}
+
+if ( getenv( 'PLUGIN_PATH' ) !== false ) {
+	define( 'PLUGIN_PATH', getenv( 'PLUGIN_PATH' ) );
+} else {
+	define( 'PLUGIN_PATH', __DIR__ . DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR );
+}
+
+require_once( getenv( 'WP_DEVELOP_DIR' ) . '/tests/phpunit/includes/functions.php' );
+
+tests_add_filter( 'muplugins_loaded', function () {
+}, 100 );
+
+putenv('WP_TESTS_DIR=' . getenv( 'WP_DEVELOP_DIR' ) . '/tests/phpunit');
+require_once( getenv( 'WC_DEVELOP_DIR' ) . '/tests/bootstrap.php' );
+
+do_action('plugins_loaded');
\ No newline at end of file
diff --git a/tests/unit/Renderer/TestSimplePhpRenderer.php b/tests/unit/Renderer/TestSimplePhpRenderer.php
new file mode 100644
index 0000000000000000000000000000000000000000..bb3f175428d5550a79b013525d17c4c2d43f1ac2
--- /dev/null
+++ b/tests/unit/Renderer/TestSimplePhpRenderer.php
@@ -0,0 +1,20 @@
+<?php
+
+use WPDesk\View\Resolver\ChainResolver;
+use WPDesk\View\Resolver\Exception\CanNotResolve;
+use WPDesk\View\Resolver\NullResolver;
+
+class TestSimplePhpRenderer extends \PHPUnit\Framework\TestCase
+{
+    const TEXT_IN_TEMPLATE = 'outputText';
+
+    const TEMPLATE_NAME = 'some_template';
+
+    const TEMPLATE_DIR = '/templates';
+
+    public function testRenderWithDirResolver()
+    {
+        $renderer = new \WPDesk\View\Renderer\SimplePhpRenderer(new \WPDesk\View\Resolver\DirResolver(__DIR__ . self::TEMPLATE_DIR));
+        $this->assertEquals(self::TEXT_IN_TEMPLATE, $renderer->render(self::TEMPLATE_NAME));
+    }
+}
\ No newline at end of file
diff --git a/tests/unit/Renderer/templates/some_template.php b/tests/unit/Renderer/templates/some_template.php
new file mode 100644
index 0000000000000000000000000000000000000000..fcd781aa62d0947505006ff55743136fd003c5d2
--- /dev/null
+++ b/tests/unit/Renderer/templates/some_template.php
@@ -0,0 +1,2 @@
+<?php
+    echo 'outputText';
\ No newline at end of file
diff --git a/tests/unit/Resolver/TestChainResolver.php b/tests/unit/Resolver/TestChainResolver.php
new file mode 100644
index 0000000000000000000000000000000000000000..3d5d51011d3764141325aabea78a63778f635794
--- /dev/null
+++ b/tests/unit/Resolver/TestChainResolver.php
@@ -0,0 +1,53 @@
+<?php
+
+use WPDesk\View\Resolver\ChainResolver;
+use WPDesk\View\Resolver\Exception\CanNotResolve;
+use WPDesk\View\Resolver\NullResolver;
+
+class TestChainResolver extends \PHPUnit\Framework\TestCase
+{
+    const RESPONSE_OF_RESOLVER = 'response';
+
+    const RESOLVE_METHOD_NAME = 'resolve';
+
+    public function setUp()
+    {
+        \WP_Mock::setUp();
+    }
+
+    public function tearDown()
+    {
+        \WP_Mock::tearDown();
+    }
+
+    public function testUseSecondResolverWhenFirstFailed()
+    {
+        $validResolver = Mockery::mock(NullResolver::class);
+        $validResolver
+            ->shouldReceive(self::RESOLVE_METHOD_NAME)
+            ->andReturn(self::RESPONSE_OF_RESOLVER);
+
+        $resolver = new ChainResolver(new NullResolver(), new NullResolver(), $validResolver);
+        $this->assertEquals(self::RESPONSE_OF_RESOLVER, $resolver->resolve('whatever.php'));
+    }
+
+    public function testUseFirstResolverFirst()
+    {
+        $validResolver = Mockery::mock(NullResolver::class);
+        $validResolver
+            ->shouldReceive(self::RESOLVE_METHOD_NAME)
+            ->andReturn(self::RESPONSE_OF_RESOLVER);
+
+        $resolver = new ChainResolver($validResolver, new NullResolver(), new NullResolver());
+        $this->assertEquals(self::RESPONSE_OF_RESOLVER, $resolver->resolve('whatever.php'));
+    }
+
+    public function testThrowExceptionWhenBothCannotFind()
+    {
+        $this->expectException(CanNotResolve::class);
+
+        $resolver = new ChainResolver(new NullResolver(), new NullResolver());
+
+        $resolver->resolve('whatever2');
+    }
+}
\ No newline at end of file
diff --git a/tests/unit/Resolver/TestDirResolver.php b/tests/unit/Resolver/TestDirResolver.php
new file mode 100644
index 0000000000000000000000000000000000000000..7c9876099f9b66247fc9d209febff09f26a5ff61
--- /dev/null
+++ b/tests/unit/Resolver/TestDirResolver.php
@@ -0,0 +1,29 @@
+<?php
+
+
+use WPDesk\View\Resolver\Exception\CanNotResolve;
+
+class TestDirResolver extends \PHPUnit\Framework\TestCase
+{
+    const TEMPLATE_NAME = 'some_template.php';
+    const TEMPLATE_FILE = 'some_template.php';
+    const TEMPLATE_SUBDIR = 'templates';
+
+
+    public function testCanFindInDirPath()
+    {
+        $dir = __DIR__ . '/' . self::TEMPLATE_SUBDIR;
+        $resolver           = new \WPDesk\View\Resolver\DirResolver($dir);
+
+        $this->assertStringEndsWith(self::TEMPLATE_FILE, $resolver->resolve(self::TEMPLATE_NAME),
+            'Template should be found in dir');
+    }
+
+    public function testThrowExceptionWhenCannotFind()
+    {
+        $this->expectException(CanNotResolve::class);
+
+        $resolver = new \WPDesk\View\Resolver\DirResolver('whatever');
+        $resolver->resolve('whatever2');
+    }
+}
\ No newline at end of file
diff --git a/tests/unit/Resolver/TestWpThemeResolver.php b/tests/unit/Resolver/TestWpThemeResolver.php
new file mode 100644
index 0000000000000000000000000000000000000000..ddcc43c5210c459d0024da728b63a0257ac2b6cd
--- /dev/null
+++ b/tests/unit/Resolver/TestWpThemeResolver.php
@@ -0,0 +1,69 @@
+<?php
+
+
+use WPDesk\View\Resolver\Exception\CanNotResolve;
+
+class TestThemeResolver extends \PHPUnit\Framework\TestCase
+{
+    const TEMPLATE_NAME = 'some_template.php';
+    const TEMPLATE_FILE = 'some_template.php';
+    const TEMPLATE_SUBDIR = 'templates';
+
+    public function setUp()
+    {
+        \WP_Mock::setUp();
+
+        \WP_Mock::userFunction('locate_template', [
+            'return' => function ($template_names, $load = false, $require_once = true) {
+                $located = '';
+                foreach ((array)$template_names as $template_name) {
+                    if ( ! $template_name) {
+                        continue;
+                    }
+                    if (file_exists(STYLESHEETPATH . '/' . $template_name)) {
+                        $located = STYLESHEETPATH . '/' . $template_name;
+                        break;
+                    }
+                }
+
+                return $located;
+            }
+        ]);
+
+        \WP_Mock::userFunction('trailingslashit', [
+            'return' => function ($string) {
+                return untrailingslashit($string) . '/';
+            }
+        ]);
+
+        \WP_Mock::userFunction('untrailingslashit', [
+            'return' => function ($string) {
+                return rtrim($string, '/\\');
+            }
+        ]);
+    }
+
+    public function tearDown()
+    {
+        \WP_Mock::tearDown();
+    }
+
+    public function testCanFindInStyleSheetPath()
+    {
+        define('STYLESHEETPATH', __DIR__);
+
+        $template_base_path = self::TEMPLATE_SUBDIR;
+        $resolver           = new \WPDesk\View\Resolver\WPThemeResolver($template_base_path);
+
+        $this->assertStringEndsWith(self::TEMPLATE_FILE, $resolver->resolve(self::TEMPLATE_NAME),
+            'Template should be found in stylesheetpath');
+    }
+
+    public function testThrowExceptionWhenCannotFind()
+    {
+        $this->expectException(CanNotResolve::class);
+
+        $resolver = new \WPDesk\View\Resolver\WPThemeResolver('whatever');
+        $resolver->resolve('whatever2');
+    }
+}
\ No newline at end of file
diff --git a/tests/unit/Resolver/templates/some_template.php b/tests/unit/Resolver/templates/some_template.php
new file mode 100644
index 0000000000000000000000000000000000000000..dd6143c8fc25443943e50fe4b90f5e86d6331a8e
--- /dev/null
+++ b/tests/unit/Resolver/templates/some_template.php
@@ -0,0 +1 @@
+this is dummy text
\ No newline at end of file
diff --git a/tests/unit/bootstrap.php b/tests/unit/bootstrap.php
new file mode 100644
index 0000000000000000000000000000000000000000..575b33bd7df4416b1684dcd7b22e6b5beb4760c6
--- /dev/null
+++ b/tests/unit/bootstrap.php
@@ -0,0 +1,6 @@
+<?php
+/**
+ * PHPUnit bootstrap file
+ */
+
+require_once __DIR__ . '/../../vendor/autoload.php';