All Projects → riezebosch → Unmockable

riezebosch / Unmockable

Licence: other
💉 ↪️ 🎁 Unmockable objects wrapping in .NET

Programming Languages

C#
18002 projects

Projects that are alternatives of or similar to Unmockable

finance-project-ddd
Projeto financeiro usando domain driven design, tdd, arquitetura hexagonal e solid
Stars: ✭ 67 (+91.43%)
Mutual labels:  tdd, solid
Alsatian
TypeScript testing framework with test cases
Stars: ✭ 244 (+597.14%)
Mutual labels:  tdd, solid
Event Sourcing Castanha
An Event Sourcing service template with DDD, TDD and SOLID. It has High Cohesion and Loose Coupling, it's a good start for your next Microservice application.
Stars: ✭ 68 (+94.29%)
Mutual labels:  tdd, solid
Dotnet New Caju
Learn Clean Architecture with .NET Core 3.0 🔥
Stars: ✭ 228 (+551.43%)
Mutual labels:  tdd, solid
clean-ts-api
API em NodeJs usando Typescript, TDD, Clean Architecture, Design Patterns e SOLID principles
Stars: ✭ 43 (+22.86%)
Mutual labels:  tdd, solid
Clean Ts Api
API em NodeJs usando Typescript, TDD, Clean Architecture, Design Patterns e SOLID principles
Stars: ✭ 619 (+1668.57%)
Mutual labels:  tdd, solid
Interviews
A list of fancy questions I've been asked during the interviews I had. Some of them I ask when interviewing people.
Stars: ✭ 140 (+300%)
Mutual labels:  tdd, solid
Aprenda Go Com Testes
Aprenda Go com desenvolvimento orientado a testes
Stars: ✭ 230 (+557.14%)
Mutual labels:  tdd
Nspec
A battle hardened testing framework for C# that's heavily inspired by Mocha and RSpec.
Stars: ✭ 242 (+591.43%)
Mutual labels:  tdd
Pester
Pester is the ubiquitous test and mock framework for PowerShell.
Stars: ✭ 2,620 (+7385.71%)
Mutual labels:  tdd
Urlhub
URL shortener web application based on the Laravel PHP Framework.
Stars: ✭ 217 (+520%)
Mutual labels:  tdd
understory.garden
Understory is a digital garden, a micro-publishing space for you to plant the seeds of your ideas and grow them into bi-directionally linked web portals. It's a social zettelkasten that lets users use Web Monetization to get paid when people spend time with their content.
Stars: ✭ 27 (-22.86%)
Mutual labels:  solid
Jasmine
Simple JavaScript testing framework for browsers and node.js
Stars: ✭ 15,261 (+43502.86%)
Mutual labels:  tdd
Clean Architecture Manga
🌀 Clean Architecture with .NET6, C#10 and React+Redux. Use cases as central organizing structure, completely testable, decoupled from frameworks
Stars: ✭ 3,104 (+8768.57%)
Mutual labels:  tdd
Junit Dataprovider
A TestNG like dataprovider runner for JUnit with many additional features
Stars: ✭ 226 (+545.71%)
Mutual labels:  tdd
mockk-guidebook
A guide to using the MockK testing library.
Stars: ✭ 37 (+5.71%)
Mutual labels:  mocks
Transport Eta
Twitch streamed 🎥playground repo, README speaks to you.
Stars: ✭ 223 (+537.14%)
Mutual labels:  tdd
Node Typescript Api
🚀Complete Node.js API built using 👉Typescript | Jest | MongoDB | Express
Stars: ✭ 234 (+568.57%)
Mutual labels:  tdd
Silsilah
A genealogy/family tree application, built with Laravel.
Stars: ✭ 246 (+602.86%)
Mutual labels:  tdd
Quiz App
A repository reflecting the progress made on the "How to Build iOS Apps with Swift, TDD & Clean Architecture" YouTube series, by Caio & Mike.
Stars: ✭ 230 (+557.14%)
Mutual labels:  tdd

build status codecov maintainability nuget stryker

📢 Shout-out

A big shoutout to Microsoft and other vendors to start unit testing your SDKs so you'll share our pain and give us some freaking extension points.

Dependency Inversion Principle One should "depend upon abstractions, not on concretions."

Please, don't give us the Unmockable<🖕>.

Support

Please, retweet to support this petition and @mention your vendor.

Unmockable

Imagine you need a dependency on a 3rd party SDK where all types carry no interfaces, and all methods are not virtual. Your only option is writing a wrapper that either implements an interface or has its methods marked virtual and does nothing more than passing through calls to the underlying object.

That's where this tiny library comes in. It acts as that handwritten wrapper for you.

Not a replacement

For dependencies under control, introduce interfaces, and use a regular mocking framework like NSubstitute or Moq. Kindly send an email to the vendor of the SDK you're using if they could pretty please introduce some interfaces. It is a no-brainer to extract an interface, and it helps us to be SOLID.

Feature slim

This library has a particular purpose and is deliberately not a full-fledged mocking framework. Therefore I try to keep its features as slim as possible, meaning:

  • All mocks are strict; each invocation requires explicit setup.
  • There are are no wild card argument matchers.
  • The API is straightforward and sparse.
  • Wrapping static classes is not supported.

That being said, I genuinely believe in pure TDD, so everything is written from a red-green-refactor cycle, and refactoring is done with SOLID principles and Design Patterns in hand. If you spot a place where another pattern could be applied, don't hesitate to let me know.

Different

What makes it different from Microsoft Fakes, Smocks, or Pose is that it only uses C# language constructs. There is no runtime rewriting or reflection/emit under the hood. Of course, this impacts the way you wrap and use your dependency, but please, don't let us clean up someone else's 💩.

Usage

I prefer NSubstitute over Moq for its crisp API. However, since we are (already) dealing with Expressions, I felt it was more convenient (and easier for me to implement) to resemble the Moq API.

💉 Inject

Inject an unmockable* object:

public class SomeLogic
{
    public SomeLogic(IUnmockable<HttpClient> client)
    {
        _client = client;
    }
}

Wrap the execution of a method in an expression:

public async Task DoSomething(int input)
{
    await _client.Execute(x => x.DownloadAsync(...));
}

* The HttpClient is just a hand-picked example and not necessarily unmockable. There have been some debate around this type. Technically it is mockable, as long as you are not afraid of message handlers.

Concrete unmockable types (pun intented) I had to deal with recently are the ExtensionManagementHttpClient and the AzureServiceTokenProvider.

↪️ Intercept

Inject an interceptor from a test using Unmockable.Intercept:

var client = Interceptor.For<HttpClient>()
    .Setup(x => x.DownloadAsync(...))
    .Returns(...);

var target = new SomeLogic(client);
await target.DoSomething(3);

client.Verify();

Note: Since v3 the API has changed in Interceptor.For to generate an interceptor for some unmockable.

Only strict 'mocks' are supported, meaning all invocations require setup, and all setups demand invocation. Using strict mocks saves you from NullReferenceExceptions and makes verification easy.

If you really want a stub instead of a mock, I'd recommend auto-mocking with AutoFixture:

var fixture = new AutoFixture();
fixture
    .Customize(new AutoConfiguredNSubstituteCustomization());

var client = fixture
    .Create<IUnmockable<HttpClient>>();

var target = new SomeLogic(client);
await target.DoSomething(3);

🎁 Wrap

Inject the wrapper object using Unmockable.Wrap:

services
    .AddTransient<IUnmockable<HttpClient>, Wrap<HttpClient>>();
services
    .AddScoped<HttpClient>();

Or wrap an existing object:

var client = new HttpClient().Wrap();

Or add wrappers for all services with Unmockable.DependencyInjection:

services
    .AddScoped<HttpClient>();
services
    .AddUnmockables();

Remark: The expressions are compiled at runtime on every invocation, so there is a performance penalty. I tried to add caching here, but that turns out not to be a sinecure.

Matchers

Collection arguments get unwrapped when matching the actual call with provided setups! Value types, anonymous types and classes with a custom GetHashCode() & Equals() should be safe. You can do custom matching with Arg.Ignore<T>(), Arg.Where<T>(x => ...) and Arg.With<T>(x => ...), though the recommendation is to be explicit as possible.

matcher description
Ignore ignore the actual value
Where match the actual value using the predicate
With do something like an assertion on the actual value

Using explicit values in the setup:

Interceptor
    .For<SomeUnmockableObject>()
    .Setup(m => m.Foo(3))
    .Returns(5);

When the actual value doesn't matter or is hard or impossible to setup:

Interceptor
    .For<SomeUnmockableObject>()
    .Setup(m => m.Foo(Arg.Ignore<int>()))
    .Returns(5);

If you need some more complex matching:

Interceptor
    .For<SomeUnmockableObject>()
    .Setup(m => m.Foo(Arg.Where<int>(x => x > 5 && x <= 10)))
    .Returns(5);

Assertion on the arguments is done using the With matcher. This is a bit of a combination of Ignore and Where, since you receive the value in the lambda but do not provide a result for the matcher.

The assertion should throw an exception when the actual value does not meet your expectations.

Interceptor
    .For<SomeUnmockableObject>()
    .Setup(m => m.Foo(Arg.With<int>(x => x.Should().Be(3, ""))))
    .Returns(5);

Mind that you need to specify values for all optionals also since expression trees may not contain calls that uses optional arguments.

Optional arguments not allowed in expressions

An expression tree cannot contain a call or invocation that uses optional arguments

You can use the default literal for all arguments (in C# 7.1.), but be aware that this is the default value of the type, which is not necessarily the same as the default value specified for the argument!

client.Execute(x => x.InstallExtensionByNameAsync("some-value", "some-value", default, default, default));

On the plus side, you now have to make it explicit both on the Execute and the Setup end making it less error-prone.

Unmockable unmockables

What if your mocked unmockable object returns an unmockable object?! Just wrap the (in this case) data fetching functionality in a separate class, test it heavily using integration tests, and inject that dependency into your current system under test.

Static classes

At first, I added, but then I removed support for 'wrapping' static classes and invoking static methods. In the end, it is not an unmockable object! If you're dependent, let's say, on DateTime.Now you can add a method overload that accepts a specific DateTime. You don't need this framework for that.

public void DoSomething(DateTime now)
{
    if (now ...) {}
}

public void DoSomething() => DoSomething(DateTime.Now)

Or with a factory method if it has to be more dynamic.

public void DoSomething(Func<DateTime> now)
{
    while (now() <= ...) {}
}

public void DoSomething() => DoSomething(() => DateTime.Now)

If you don't like this change in your public API, you can extract an interface and only include the second method (which is a good idea anyway), or you mark the overloaded method internal and expose it to your test project with the [InternalsVisibleTo] attribute.


Happy coding!

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].