diff --git a/src/Generator/Utils/TestsUtils.cs b/src/Generator/Utils/TestsUtils.cs
new file mode 100644
index 00000000..79af15c3
--- /dev/null
+++ b/src/Generator/Utils/TestsUtils.cs
@@ -0,0 +1,52 @@
+using System.IO;
+using Cxxi.Generators;
+
+namespace Cxxi.Utils
+{
+    public abstract class LibraryTest : ILibrary
+    {
+        readonly string name;
+        readonly LanguageGeneratorKind kind;
+
+        public LibraryTest(string name, LanguageGeneratorKind kind)
+        {
+            this.name = name;
+            this.kind = kind;
+        }
+
+        public virtual void Setup(DriverOptions options)
+        {
+            options.LibraryName = name + ".Native";
+            options.GeneratorKind = kind;
+            options.OutputDir = "../gen/" + name;
+            options.GenerateLibraryNamespace = false;
+
+            var path = "../../../tests/" + name;
+            options.IncludeDirs.Add(path);
+
+            var files = Directory.EnumerateFiles(path, "*.h");
+            foreach(var file in files)
+                options.Headers.Add(Path.GetFileName(file));
+        }
+
+        public virtual void Preprocess(Library lib)
+        {
+        }
+
+        public virtual void Postprocess(Library lib)
+        {
+        }
+
+        public virtual void SetupPasses(Driver driver, PassBuilder passes)
+        {
+        }
+
+        public virtual void GenerateStart(TextTemplate template)
+        {
+        }
+
+        public virtual void GenerateAfterNamespaces(TextTemplate template)
+        {
+        }
+    }
+}
diff --git a/tests/Hello/Hello.Tests.cs b/tests/Hello/Hello.Tests.cs
index 3f4f217c..7e9e7acb 100644
--- a/tests/Hello/Hello.Tests.cs
+++ b/tests/Hello/Hello.Tests.cs
@@ -1,13 +1,43 @@
-using System;
+using NUnit.Framework;
 
+[TestFixture]
 public class HelloTests
 {
-    public static void Main (String[] args)
+    [Test]
+    public void TestHello()
     {
         var hello = new Hello();
         hello.PrintHello("Hello world");
 
-        Console.WriteLine("True =" + hello.test1(3, 3.0f).ToString());
-        Console.WriteLine("False =" + hello.test1(2, 3.0f).ToString());
+        Assert.That(hello.add(1, 1), Is.EqualTo(2));
+        Assert.That(hello.add(5, 5), Is.EqualTo(10));
+
+        Assert.IsTrue(hello.test1(3, 3.0f));
+        Assert.IsFalse(hello.test1(2, 3.0f));
+
+        var foo = new Foo { A = 4, B = 7 };
+        Assert.That(hello.AddFoo(foo), Is.EqualTo(11));
+        Assert.That(hello.AddFooPtr(foo), Is.EqualTo(11));
+        Assert.That(hello.AddFooRef(foo), Is.EqualTo(11));
+
+        var bar = new Bar { A = 4, B = 7 };
+        Assert.That(hello.AddBar(bar), Is.EqualTo(11));
+
+        var retFoo = hello.RetFoo(7, 2.0f);
+        Assert.That(retFoo.A, Is.EqualTo(7));
+        Assert.That(retFoo.B, Is.EqualTo(2.0));
+
+        var foo2 = new Foo2 {A = 4, B = 2, C = 3};
+        Assert.That(hello.AddFoo(foo2), Is.EqualTo(6));
+        Assert.That(hello.AddFoo2(foo2), Is.EqualTo(9));
+
+        var bar2 = new Bar2 { A = 4, B = 7, C = 3 };
+        Assert.That(hello.AddBar2(bar2), Is.EqualTo(14));
+    }
+
+    static void Main(string[] args)
+    {
+        var hello = new Hello();
     }
 }
+ 
\ No newline at end of file
diff --git a/tests/Hello/Hello.cpp b/tests/Hello/Hello.cpp
index 823f1e8d..c80316f5 100644
--- a/tests/Hello/Hello.cpp
+++ b/tests/Hello/Hello.cpp
@@ -1,18 +1,67 @@
-#include <iostream>
 #include "Hello.h"
 
-using namespace std;
+Foo::Foo()
+{
+}
+
+Bar::Bar()
+{
+}
 
 Hello::Hello ()
 {
+    //cout << "Ctor!" << "\n";
 }
 
 void Hello::PrintHello(const char* s)
 {
-	cout << "PrintHello: " << s << "\n";
+    //cout << "PrintHello: " << s << "\n";
 }
 
 bool Hello::test1(int i, float f)
 {
     return i == f;
 }
+
+int Hello::add(int a, int b)
+{
+    return a + b;
+}
+
+int Hello::AddFoo(Foo foo)
+{
+    return (int)(foo.A + foo.B);
+}
+
+int Hello::AddFooRef(Foo& foo)
+{
+    return AddFoo(foo);
+}
+
+int Hello::AddFooPtr(Foo* foo)
+{
+    return AddFoo(*foo);
+}
+
+int Hello::AddFoo2(Foo2 foo)
+{
+    return (int)(foo.A + foo.B + foo.C);
+}
+
+int Hello::AddBar(Bar bar)
+{
+    return (int)(bar.A + bar.B);
+}
+
+int Hello::AddBar2(Bar2 bar)
+{
+    return (int)(bar.A + bar.B + bar.C);
+}
+
+Foo Hello::RetFoo(int a, float b)
+{
+    Foo foo;
+    foo.A = a;
+    foo.B = b;
+    return foo;
+}
\ No newline at end of file
diff --git a/tests/Hello/Hello.cs b/tests/Hello/Hello.cs
index 05157825..93d762ae 100644
--- a/tests/Hello/Hello.cs
+++ b/tests/Hello/Hello.cs
@@ -1,45 +1,19 @@
 using Cxxi.Generators;
-using Cxxi.Passes;
+using Cxxi.Utils;
 
 namespace Cxxi.Tests
 {
-    class Hello : ILibrary
+    public class Hello : LibraryTest
     {
-        private readonly LanguageGeneratorKind kind;
-
         public Hello(LanguageGeneratorKind kind)
-        {
-            this.kind = kind;
-        }
-
-        public void Setup(DriverOptions options)
-        {
-            options.LibraryName = "Hello";
-            options.GeneratorKind = kind;
-            options.OutputDir = kind == LanguageGeneratorKind.CPlusPlusCLI ?
-                "cli" : "cs";
-            options.Headers.Add("Hello.h");
-            options.IncludeDirs.Add("../../../examples/Hello");
-        }
-
-        public void Preprocess(Library lib)
-        {
-        }
-
-        public void Postprocess(Library lib)
-        {
-        }
-
-        public void SetupPasses(Driver driver, PassBuilder p)
-        {
-        }
-
-        public void GenerateStart(TextTemplate template)
+            : base("Hello", kind)
         {
         }
 
-        public void GenerateAfterNamespaces(TextTemplate template)
+        public override void Preprocess(Library lib)
         {
+            lib.SetClassAsValueType("Bar");
+            lib.SetClassAsValueType("Bar2");
         }
 
         static class Program
diff --git a/tests/Hello/Hello.h b/tests/Hello/Hello.h
index 859c8d33..fc604330 100644
--- a/tests/Hello/Hello.h
+++ b/tests/Hello/Hello.h
@@ -1,14 +1,55 @@
+//#include <string>
+
 #if defined(_MSC_VER)
 #define CXXI_API __declspec(dllexport)
 #else
-#define CXXI_API 
+#define CXXI_API
 #endif
 
+class CXXI_API Foo
+{
+public:
+
+    Foo();
+    int A;
+    float B;
+};
+
+class CXXI_API Foo2 : public Foo
+{
+public:
+
+    int C;
+};
+
+struct CXXI_API Bar
+{
+    Bar();
+    int A;
+    float B;
+};
+
+struct CXXI_API Bar2 : public Bar
+{
+    int C;
+};
+
 class CXXI_API Hello
 {
 public:
-	Hello ();
+    Hello ();
+
+    void PrintHello(const char* s);
+    bool test1(int i, float f);
+    int add(int a, int b);
+
+    int AddFoo(Foo);
+    int AddFooRef(Foo&);
+    int AddFooPtr(Foo*);
+    Foo RetFoo(int a, float b);
+
+    int AddFoo2(Foo2);
 
-	void PrintHello(const char* s);
-	bool test1(int i, float f);
+    int AddBar(Bar);
+    int AddBar2(Bar2);
 };
diff --git a/tests/Hello/Interop.h b/tests/Hello/Interop.h
deleted file mode 100644
index 4572a509..00000000
--- a/tests/Hello/Interop.h
+++ /dev/null
@@ -1,203 +0,0 @@
-// ------------------------------------------------------------------------------------------- //
-// clix.hpp (from http://blog.nuclex-games.com/mono-dotnet/cxx-cli-string-marshaling)
-//
-// Marshals strings between .NET and C++ using C++/CLI (Visual C++ 2005 and later only).
-// Faster and cleaner than the System::Interop method because it uses garbage collected memory.
-// Use at your own leisure. No warranties whatsoever provided.
-//
-// Original code by Markus Ewald
-// Updated version including several improvements suggested by Neil Hunt
-//
-// Licensed under the IBM CPL (free of charge, closed source commercial use is okay)
-// ------------------------------------------------------------------------------------------- //
-#pragma once
-
-#include <string>
-#include <vcclr.h>
-
-// CLI extensions namespace
-namespace clix {
-
-  /// <summary>Encoding types for strings</summary>
-  enum Encoding {
-
-    /// <summary>ANSI encoding</summary>
-    /// <remarks>
-    ///   This is the default encoding you've most likely been using all around in C++. ANSI
-    ///   means 8 Bit encoding with character codes depending on the system's selected code page.
-    /// <remarks>
-    E_ANSI,
-
-    /// <summary>UTF-8 encoding</summary>
-    /// <remarks>
-    ///   This is the encoding commonly used for multilingual C++ strings. All ASCII characters
-    ///   (0-127) will be represented as single bytes. Be aware that UTF-8 uses more than one
-    ///   byte for extended characters, so std::string::length() might not reflect the actual
-    ///   length of the string in characters if it contains any non-ASCII characters.
-    /// <remarks>
-    E_UTF8,
-
-    /// <summary>UTF-16 encoding</summary>
-    /// <remarks>
-    ///   This is the suggested to be used for marshaling and the native encoding of .NET
-    ///   strings. It is similar to UTF-8 but uses a minimum of two bytes per character, making
-    ///   the number of bytes required for a given string better predictable. Be aware, however,
-    ///   that UTF-16 can still use more than two bytes for a character, so std::wstring::length()
-    ///   might not reflect the actual length of the string.
-    /// </remarks>
-    E_UTF16, E_UNICODE = E_UTF16
-
-  };
-
-  // Ignore this if you're just scanning the headers for informations!
-  /* All this template stuff might seem like overkill, but it is well thought out and enables
-     you to use a readable and convenient call while still keeping the highest possible code
-     efficiency due to compile-time evaluation of the required conversion path.
-  */
-  namespace detail {
-
-    // Get C++ string type for specified encoding
-    template<Encoding encoding> struct StringTypeSelector;
-    template<> struct StringTypeSelector<E_ANSI> { typedef std::string Type; };
-    template<> struct StringTypeSelector<E_UTF8> { typedef std::string Type; };
-    template<> struct StringTypeSelector<E_UTF16> { typedef std::wstring Type; };
-
-    // Compile-time selection depending on whether a string is managed
-    template<typename StringType> struct IfManaged {
-      struct Select {
-        template<typename TrueType, typename FalseType>
-        struct Either { typedef FalseType Type; };
-      };
-      enum { Result = false };
-    };
-    template<> struct IfManaged<System::String ^> {
-      struct Select {
-        template<typename TrueType, typename FalseType>
-        struct Either { typedef TrueType Type; };
-      };
-      enum { Result = true };
-    };
-
-    // Direction of the marshaling process
-    enum MarshalingDirection {
-      CxxFromNet,
-      NetFromCxx
-    };
-
-    // The actual marshaling code
-    template<MarshalingDirection direction> struct StringMarshaler;
-
-    // Marshals to .NET from C++ strings
-    template<> struct StringMarshaler<NetFromCxx> {
-
-      template<Encoding encoding, typename SourceType>
-      static System::String ^marshal(const SourceType &string) {
-        // Constructs a std::[w]string in case someone gave us a char * to choke on
-        return marshalCxxString<encoding, SourceType>(string);
-      }
-
-      template<Encoding encoding, typename SourceType>
-      static System::String ^marshalCxxString(
-        const typename StringTypeSelector<encoding>::Type &cxxString
-      ) {
-        typedef typename StringTypeSelector<encoding>::Type SourceStringType;
-        size_t byteCount = cxxString.length() * sizeof(SourceStringType::value_type);
-
-		if(byteCount == 0) return System::String::Empty;
-
-        // Copy the C++ string contents into a managed array of bytes
-        array<unsigned char> ^bytes = gcnew array<unsigned char>(byteCount);
-        { pin_ptr<unsigned char> pinnedBytes = &bytes[0];
-          memcpy(pinnedBytes, cxxString.c_str(), byteCount);
-        }
-
-        // Now let one of .NET's encoding classes do the rest
-        return decode<encoding>(bytes);
-      }
-
-      private:
-        // Converts a byte array based on the selected encoding
-        template<Encoding encoding> static System::String ^decode(array<unsigned char> ^bytes);
-        template<> static System::String ^decode<E_ANSI>(array<unsigned char> ^bytes) {
-          return System::Text::Encoding::Default->GetString(bytes);
-        }
-        template<> static System::String ^decode<E_UTF8>(array<unsigned char> ^bytes) {
-          return System::Text::Encoding::UTF8->GetString(bytes);
-        }
-        template<> static System::String ^decode<E_UTF16>(array<unsigned char> ^bytes) {
-          return System::Text::Encoding::Unicode->GetString(bytes);
-        }
-    };
-
-    // Marshals to C++ strings from .NET
-    template<> struct StringMarshaler<CxxFromNet> {
-
-      template<Encoding encoding, typename SourceType>
-      static typename detail::StringTypeSelector<encoding>::Type marshal(
-        System::String ^string
-      ) {
-        typedef typename StringTypeSelector<encoding>::Type StringType;
-
-        // First, we use .NET's encoding classes to convert the string into a byte array
-        array<unsigned char> ^bytes = encode<encoding>(string);
-
-        if(bytes->Length == 0) return StringType();
-
-        // Then we construct our native string from that byte array
-        pin_ptr<unsigned char> pinnedBytes(&bytes[0]);
-        return StringType(
-          reinterpret_cast<StringType::value_type *>(static_cast<unsigned char *>(pinnedBytes)),
-          bytes->Length / sizeof(StringType::value_type)
-        );
-      }
-
-      template<> static std::wstring marshal<E_UTF16, System::String ^>(
-        System::String ^string
-      ) {
-        // We can directly accesss the characters in the managed string
-        pin_ptr<const wchar_t> pinnedChars(::PtrToStringChars(string));
-        return std::wstring(pinnedChars, string->Length);
-      }
-
-      private:
-        // Converts a string based on the selected encoding
-        template<Encoding encoding> static array<unsigned char> ^encode(System::String ^string);
-        template<> static array<unsigned char> ^encode<E_ANSI>(System::String ^string) {
-          return System::Text::Encoding::Default->GetBytes(string);
-        }
-        template<> static array<unsigned char> ^encode<E_UTF8>(System::String ^string) {
-          return System::Text::Encoding::UTF8->GetBytes(string);
-        }
-        template<> static array<unsigned char> ^encode<E_UTF16>(System::String ^string) {
-          return System::Text::Encoding::Unicode->GetBytes(string);
-        }
-
-    };
-
-  } // namespace detail
-
-  // ----------------------------------------------------------------------------------------- //
-  // clix::marshalString()
-  // ----------------------------------------------------------------------------------------- //
-  /// <summary>Marshals strings between .NET managed and C++ native</summary>
-  /// <remarks>
-  ///   This all-in-one function marshals native C++ strings to .NET strings and vice versa.
-  ///   You have to specify an encoding to use for the conversion, which always applies to the
-  ///   native C++ string as .NET always uses UTF-16 for its own strings.
-  /// </remarks>
-  /// <param name="string">String to be marshalled to the other side</param>
-  /// <returns>The marshaled representation of the string</returns>
-  template<Encoding encoding, typename SourceType>
-  typename detail::IfManaged<SourceType>::Select::Either<
-    typename detail::StringTypeSelector<encoding>::Type,
-    System::String ^
-  >::Type marshalString(SourceType string) {
-
-    // Pass on the call to our nifty template routines
-    return detail::StringMarshaler<
-      detail::IfManaged<SourceType>::Result ? detail::CxxFromNet : detail::NetFromCxx
-    >::marshal<encoding, SourceType>(string);
-
-  }
-
-} // namespace clix
diff --git a/tests/Hello/premake4.lua b/tests/Hello/premake4.lua
index 7ab72428..7918ed76 100644
--- a/tests/Hello/premake4.lua
+++ b/tests/Hello/premake4.lua
@@ -1,6 +1,2 @@
-group "Hello"
-  SetupTestGeneratorProject("Hello", "Hello.cs")
-  SetupTestNativeProject("Hello.Native", { "Hello.cpp", "Hello.h" })
-  SetupTestProjects("Hello", { "Hello.Tests.cs"})
-
-
+group "Tests/Hello"
+  SetupTestProject("Hello")
\ No newline at end of file