Giter Site home page Giter Site logo

automoqer's Introduction

This repository contains a nuget package called "Automoqer": https://www.nuget.org/packages/Automoqer/

About Automoqer

The purpose of Automoqer is to ease the creation of services with constructor IoC in unit testing.

Basic usage

  1. Get Automoqer via NuGet: NuGet

  2. In your unit test, create an Automoqer instance like this:

using (var serviceMocker = new AutoMoqer<ServiceToCreate>().Build())
{	
	//Example definition of a dependency mock setup:
	serviceMocker.Param<ICustomerRepository>().Setup(m => m.FindCustomer(It.Is<int>(p => p == 1))).Returns(new Customer());

	//Access the service instance:
	var service = serviceMocker.Service;

	//Example verification of a method call
	serviceMocker.Param<ILogger>().Verify(m => m.Log(It.IsAny<string>));
}

Why using Automoqer

If your services are defined like this:

public class CustomerService 
{
	private readonly ILogger _logger;
	private readonly IUnitOfWork _unitOfWork;
	private readonly IAnotherDependency _anotherDependency;

	public CustomerService(
		ILogger logger,
		IUnitOfWork unitOfWork,
		IAnotherDependency anotherDependency	
	) 
	{
		_logger = logger;
		_unitOfWork = unitOfWork;
		_anotherDependency = anotherDependency;
	}

	//...
}

Then chances are that you have a lot of unit tests that looks like this:

[Fact]
public CreateNewCustomerSuccessfully()
{
	var loggerMock = new Mock<ILogger>();
	var unitOfWorkMock = new Mock<IUnitOfWork>();
	var anotherDependencyMock = new Mock<IAnotherDependency>();

	//Your Moq .Setup are defined here..

	var service = new CustomerService(
		loggerMock.Object,
		unitOfWorkMock.Object,
		anotherDependencyMock.Object
	);

	//Actual test-case goes here...

	//Your Moq .Verify are defined here...
}

This is quite tedious to write and if you need to change the service's dependencies, you'll have a lot of test cases to change.

Automoqer removes this boilerplate for you by automatically create a Service with its constructor parameters as Moq-objects:

[Fact]
public CreateNewCustomerSuccessfully()
{
    using (var serviceMocker = new AutoMoqer<CustomerService>().Build())
    {
		//Your Moq .Setup are defined here..
		//Mocks accessed by serviceMocker.Param<ILogger>().Setup(...

		//Actual test-case goes here...
		//Service accessed by serviceMocker.Service

		//Your Moq .Verify are defined here...
	}	
}

It also runs VerifyAll() on all Moq-objects in its Dispose-method (hence the IDisposable-pattern)

Advanced usage

Provide parameter instances

You can make exceptions from having Automoqer automatically create Moq-objects from all constructor parameters. This is done by using one of the .With methods available on the AutoMoqer instance. Please note that these exceptions will not be available through the .Param method on the Automoqer-container.

By parameter type

This is how you provide your own instance of a parameter by it's type:

var logger = new TestLogger();

using (var serviceMocker = new AutoMoqer<CustomerService>()
	.With<ILogger>(logger)
	.Build())
{
	//...
}

By parameter name

This is how you provide your own instance of a parameter by it's type:

var logger = new TestLogger();

using (var serviceMocker = new AutoMoqer<CustomerService>()
	.With("logger", logger)
	.Build())
{
	//...
}			

Contributors

License and usage

MIT License

Copyright (c) 2016 Robert Bengtsson

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

automoqer's People

Contributors

manne avatar rbengtsson avatar smatsson avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

automoqer's Issues

improved support for aaa pattern

I like the aaa pattern. automoqer has still room for improvement regarding to support this pattern. To apply the aaa pattern, a comment has to be written before the end of the using block.

void Main()
{
	// Arrange
	using(var moqer = new AutoMoqer<EventConsumer>().Build())
	{
		moqer.Param<IDependency>().Setup(d => d.Register());
		
		// Act
		moqer.Param<ICrazyEventEmiter>().Raise(e => e.Foo += null, EventArgs.Empty);
		
		// Assert
		// is done in moqer.Dispose()
	}
}

public class EventConsumer
{
	public EventConsumer(ICrazyEventEmiter eventEmiter, IDependency dependency)
	{
		eventEmiter.Foo += (sender, args) =>
		{
			dependency.Register();
		};
	}	
}

public interface IDependency
{
	void Register();
}

public interface ICrazyEventEmiter
{
	event EventHandler Foo;
}

A possibility is to introduce an explicit method to call the verification, like AutoMoqerContainer<TService>.VerifyAll():void . The disadvantage is that the verification is done twice. This can be mitigated by introducing a class which does not implicitly invoke the verification, e.g AutoMoqerContainerWithExplicitVerification<TService>.

@rbengtsson if you want to have this feature, I will send an PR. As always I am opened for suggestions and/or further improvement. Especially in nomenclature ๐Ÿ˜‰

Verification does not work, if Service is not created

Given the following code

void Main()
{
	using(var moqer = new AutoMoqer<EventConsumer>().Build())
	{
		moqer.Param<IDependency>().Setup(d => d.Register());
		moqer.Param<ICrazyEventEmiter>().Raise(e => e.Foo += null, EventArgs.Empty);
	}
}

public class EventConsumer
{
	public EventConsumer(ICrazyEventEmiter eventEmiter, IDependency dependency)
	{
		eventEmiter.Foo += (sender, args) =>
		{
			dependency.Register();
		};
	}	
}

public interface IDependency
{
	void Register();
}

public interface ICrazyEventEmiter
{
	event EventHandler Foo;
}

Running this snippet with LINQPad will result in MockException: The following setups were not matched: IDependency d => d.Register()
Reason: the service (instance of EventConsumer) is not created.

Changing the code to the following, the expected behavior is met.

void Main()
{
	using(var moqer = new AutoMoqer<EventConsumer>().Build())
	{
                var unused = moqer.Service;
		moqer.Param<IDependency>().Setup(d => d.Register());
		moqer.Param<ICrazyEventEmiter>().Raise(e => e.Foo += null, EventArgs.Empty);
	}
}

// ...

However SonarQube/SonarLint reports a violation S1481.

An improvement would be to have a method, like AutoMoqerContainer<TService>.CreateService():void, which internally creates the instance.

@rbengtsson if you want to have this feature, I will send an PR. As always I am opened for suggestions and/or further improvement.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.