Making AutoMoq return Fixture-created values for methods - moq

I'd like to explore wether we can save time by setting that all Moq-mocks created by AutoMoq should by default return Fixture-created values as method return values.
This would be beneficial when doing a test like the following:
[TestMethod]
public void Client_Search_SendsRestRequest()
var client = fixture.Create<Client>();
// Could be removed by implementing the mentioned functionality
Mock.Of(JsonGenerator).Setup(j => j.Search(It.IsAny<string>())).Returns(create("JsonBody")));
client.Search(fixture.Create("query"));
Mock.Of(client.RestClient).Verify(c => c.Execute(It.IsAny<RestRequest>()));
Mock.Of(client.RestClient).Verify(c => c.Execute(It.Is<RestRequest>(r => record(r.Body) == record(client.JsonGenerator.Search(query)))));
}
Note that the generated values must be cached inside (?) the proxies, we want the same value "frozen" in order to check. Also, setting up the mock with Setup should override the created value.
So, how can we modify AutoMoq mocks to do this?
A simple test verifying that it works could be:
[TestMethod]
public void MockMethodsShouldReturnCreatedValues()
{
Guid.Parse(new Fixture().Create<ITest>().Test());
}
public interface ITest
{
string Test();
}

Definitely possible, just use the AutoConfiguredMoqCustomization instead of the AutoMoqCustomization. The mocks will use the fixture to generate returns values for all its methods, properties and indexers (*).
Properties will be evaluated eagerly, whereas indexers/methods' return values will be evaluated and cached when invoked for this first time.
(*) There are two exceptions to this rule - the customization cannot automatically setup generic methods or methods with ref parameters, as explained here. You'll have to set those up manually, with the help of the .ReturnsUsingFixture method.

Related

How do I prevent phpunit from overriding method type-hints

I have a wrapper that gives me a more convenient API to create mocks. You can ignore the implementation details. Just note the fact that:
it's a trait used on my test classes
the method used to obtain the mock is type-hinted
trait MockFacilitator {
protected function positiveStub (string $target, array $overrides, array $constructorArguments = []):MockBuilder {
$builder = $this->getBuilder($target, $constructorArguments, $overrides);
$this->stubSingle($overrides, $builder);
return $builder;
}
private function stubSingle (array $overrides, MockBuilder $builder):void {
foreach ($overrides as $method => $newValue)
$builder->expects($this->any())
->method($method)->will($this->returnValue($newValue));
}
private function getBuilder (string $target, array $constructorArguments, array $methodsToRetain):MockBuilder {
$builder = $this->getMockBuilder($target);
if (!empty($constructorArguments))
$builder->setConstructorArgs($constructorArguments);
if (!empty($methodsToRetain))
$builder->setMethods(array_keys($methodsToRetain));
return $builder->getMock();
}
Used in my tests like so
$handler = $this->positiveStub(LoginRequestHandler::class, ["isValidRequest" => true]);
Now, the generated stub not only creates the new class that I want (LoginRequestHandler) , but creates new classes for the method return types as well(MockBuilder) ! As is explained on this thread https://stackoverflow.com/a/39070492, such code will not compile.
Is it that phpunit dislikes type hinting method return types? I have seen on other threads that arguments with reference types will equally be overwritten; although in their case, the type was removed altogether, citing inability of phpunit to load those types as the reason. In my case, it probably mocks those return types as well
Is there a way to restrict type generation to only what goes into the mock builder? I prefer to leave out everything else as is in my original class
MockBuilder::disableAutoReturnValueGeneration() can be used to disable the automatic return value generation. The requires using the Mock Builder API instead of createStub(), createMock(), etc., of course.
Of course, automatic return value generation is not triggered, even when it is enabled, which is the default, when you explicitly configure return values for your stubs.

Mock.Verify does not identify call made to mock service provided by IServiceProvider

I'm trying to write an integration test for a service method. The test compiles and runs without error, but it says that the number of calls that match the predicate are 0.
Test setup:
[TestCase]
public void Save_Submission_Processing_And_ClientGroupMapping_Type()
{
Mock<ISubmissionRepository> submissionRepositoryMock = new Mock<ISubmissionRepository>();
submissionRepositoryMock.Setup(x => x.GetOne(It.IsAny<Guid>())).Returns(QueryResult<Submission>.Ok(new Submission()));
IServiceCollection services = new ServiceCollection();
services.AddSingleton(x => submissionRepositoryMock.Object);
ClientGroupMappingService clientGroupMappingService = new ClientGroupMappingService(services.BuildServiceProvider());
clientGroupMappingService.ProcessClientGroupMappingImport(Guid.NewGuid());
submissionRepositoryMock.Verify(c => c.Save(It.Is<Submission>(d => d.SubmissionStatus == SubmissionStatus.Processing)), Times.Once);
}
Unit under test:
public class ClientGroupMappingService : IClientGroupMappingService
{
private readonly ISubmissionRepository _submissionRepository;
public ClientGroupMappingService(IServiceProvider serviceProvider)
{
_submissionRepository = serviceProvider.GetRequiredService<ISubmissionRepository>();
}
public void ProcessClientGroupMappingImport(Guid submissionID)
{
Submission submission = _submissionRepository.GetOne(submissionID).Value;
submission.SubmissionStatus = SubmissionStatus.Processing;
_submissionRepository.Save(submission);
// ..other stuff
}
}
Moq.MockException :
Expected invocation on the mock once, but was 0 times: c => c.Save(It.Is<Submission>(d => (int)d.SubmissionStatus == 2))
So Verify should see that the call was made to Save, and the param passed to Save matches the condition in the supplied predicate. My knee-jerk reaction is that once I pull the object out of the mock using submissionRepositoryMock.Object, I am no longer tracking the Mock, so calls to the Object are not going to register on the Mock. But if this is the case, what is the correct way to verify that my method made the required call?
The issue was in the "// ...other stuff" that I took out for brevity.
Later on in the method, the SubmissionStatus is updated again, and Mock.Verify only seems to be evaluating the REFERENCE to the object that was passed into the Save call as opposed to the VALUE, as all of the Invocations of Save show that it was called with SubmissionStatus.Success (which isn't actually true).
Hope this makes sense and helps anyone with a similar problem.

Injecting an arbitrary parameter to a service

I'm wondering if there is a sort of best practice for the following case.
For instance, I have several services and inject them all as an array into a "factory" service. Then I call a method of this factory and want to get only one service depends on some conditions. After that I execute this service and get a result...
However, some of these services require a random string that I get from a client's request.
Of cause, I can call a service's method with this string as a parameter but several services do not require this string and I'll get "unused variable" in the method.
I guess that I could get service from the factory and then call a setter to add this string into the service. But it does not look like a stateless service.
Is there a more elegant solution to pass parameters that I could not inject into service nor use the setter for it?
Here how it looks in my code
First, I have an interface of all servers that I want to check. The service should support a customer an then it should render information from a DTO.
interface Renderable {
public function supports(Customer $customer);
public function render(CustomerDTO $dto);
}
Next, I have several services. This one uses DTO to render data.
class ServiceOne implements Renderable
{
public function suppots(Customer $customer)
{
return $customer->getPriority() === 1;
}
public function render(CustomerDTO $dto)
{
return 'One: '.$dto->getName();
}
}
However, some services do not need any DTO to render, they just provide a hardcoded value.
class ServiceTwo implements Renderable
{
public function suppots(Customer $customer)
{
return $customer->getPriority() !== 1;
}
// service does not use DTO, it simply output result
// so, I'll get a notice about unused variable
// and I can not remove it from the method since it is in interface
public function render(CustomerDTO $dto)
{
return 'Two';
}
}
This is a factory. It has all services injected as an array. Then it checks and returns the first service that supports a customer instance.
class ServiceFactory
{
/** #var Renderable[] */
private $services;
public function __construct(iterable $services)
{
$this->services = $services;
}
public function getRenderer(Customer $customer)
{
foreach ($this->services as $service)
{
if ($service->supports($customer)
{
return $service;
}
}
}
}
Here like I use factory and its result
$customer = ...; // it comes from a database
$request = ...; // it comes from a http request
$renderService = $factory->getRenderer($customer);
$customerDTO = CustomerDTO::createFromData([
'customerUid' => $customer->getUid(),
'date' => new \DateTime(),
'name' => $request->getSheetUid(),
'tags' => $request->getTags(),
]);
$renderService->render($customerDTO);
So, I have to call Renderer::render with a DTO instance. But some services do not use it to "render" data. I also can not inject it into a renderer service since this object (DTO) is built in a runtime when all services already injected. I also can not inject a RequestStack into service.
Since your parameter came from request - it can't be directly injected into service. Depending on actual logic of your services you can consider one of approaches listed below. Let's call your "random string that came from a client's request" a $requestParam for further reference.
In both cases you will need to get your $requestParam from actual Request object and pass it somewhere else. It can be done in a different ways, I would propose to create listener (e.g. RequestParamListener) for kernel.request event and put here a piece of code that takes parameter from Request and pass it further into this listener. Into approaches listed below I will assume that $requestParam will be passed in this way.
1. Separate provider
You can create separate class (e.g. RequestParamProvider) that will act as provider of this $requestParam for other services. It will receive $requestParam from RequestParamListener and other services that needs to get $requestParam will need to inject this provider and use its getRequestParam() method to obtain required parameter.
From my point of view it is the simplest approach and I would recommend it.
2. Direct injection by factory
Since you have some factory service - you can pass this $requestParam directly into factory and let it to initialize other services. Less flexible because you will need to implement initialization logic by itself and maintain it while project evolves.
3. Direct injection using interface
You can create separate interface (e.g. RequestParamAwareInterface) that will contain setRequestParam() method and let all classes that needs this $requestParam to implement this interface. After that you will need to write separate compiler pass that will collect all such classes (by iterating over ContainerBuilder and looking for implementation of particular interface by class inside service's definition) and pass array of these services to your RequestParamListener. Listener in its turn will be obligated to pass $requestParam for each of given services.
This approach will let your application to grow without need to sync $requestParam injection logic. However it will came at a cost of preliminary instantiation of all affected services regardless of actual further use of created instances.

An example (or several) about method at() in phpunit

Would anybody, please, show me an example for at method in phpunit test doubles. I don't understand what is its purpose?
The purpose of the at() function is to specify the order that methods on a mock should be called. If you were to use once() or exactly(), the test would pass no matter which order the methods were called as PHPUnit is only checking that they are called during the test not when.
For example:
class FooTest extends PHPUnitTestCase {
public function testProperOrderOfMethods() {
$mockObject = $this->getMockBuilder('BarObject')
->setMethods(['baz', 'boz'])
->getMock();
$mockObject->expects($this->at(0))
->method('boz');
$mockObject->expects($this->at(1))
->method('bar');
$sut = new Foo();
$sut->methodBeingTested($mockObject);
}
This requires that our function needs to look like:
public function methodBeingTested($dependecy) {
$dependency->boz();
$dependency->bar();
}
And would fail if the function order were changed.
An example use case might be your class is using an object that connects to a service and retrieves data. You would want to have the connection opened, retrieve the data, and then close the connection. Or it may need to make further requests depending on the response. Either way all of these actions need to happen in a specific order so in your test, you would use at().

Access/use the same object during a request - asp.net

i have a HttpModule that creates an CommunityPrincipal (implements IPrincipal interface) object on every request. I want to somehow store the object for every request soo i can get it whenever i need it without having to do a cast or create it again.
Basically i want to mimic the way the FormsAuthenticationModule works.
It assigns the HttpContext.User property an object which implements the IPrincipal interface, on every request.
I somehow want to be able to call etc. HttpContext.MySpecialUser (or MySpecialContext.MySpecialUser - could create static class) which will return my object (the specific type).
I could use a extension method but i dont know how to store the object so it can be accessed during the request.
How can this be achieved ?
Please notice i want to store it as the specific type (CommunityPrincipal - not just as an object).
It should of course only be available for the current request being processed and not shared with all other threads/requests.
Right now i assign my CommunityPrincipal object to the HttpContext.User in the HttpModule, but it requires me to do a cast everytime i need to use properties on the CommunityPrincipal object which isnt defined in the IPrincipal interface.
I'd recommend you stay away from coupling your data to the thread itself. You have no control over how asp.net uses threads now or in the future.
The data is very much tied to the request context so it should be defined, live, and die along with the context. That is just the right place to put it, and instantiating the object in an HttpModule is also appropriate.
The cast really shouldn't be much of a problem, but if you want to get away from that I'd highly recommend an extension method for HttpContext for this... this is exactly the kind of situation that extension methods are designed to handle.
Here is how I'd implement it:
Create a static class to put the extension method:
public static class ContextExtensions
{
public static CommunityPrinciple GetCommunityPrinciple(this HttpContext context)
{
if(HttpContext.Current.Items["CommunityPrinciple"] != null)
{
return HttpContext.Current.Items["CommunityPrinciple"] as CommunityPrinciple;
}
}
}
In your HttpModule just put the principal into the context items collection like:
HttpContext.Current.Items.Add("CommunityPrincipal", MyCommunityPrincipal);
This keeps the regular context's user property in the natural state so that 3rd party code, framework code, and anything else you write isn't at risk from you having tampered with the normal IPrincipal stroed there. The instance exists only during the user's request for which it is valid. And best of all, the method is available to code as if it were just any regular HttpContext member.... and no cast needed.
Assigning your custom principal to Context.User is correct. Hopefully you're doing it in Application_AuthenticateRequest.
Coming to your question, do you only access the user object from ASPX pages? If so you could implement a custom base page that contains the cast for you.
public class CommunityBasePage : Page
{
new CommunityPrincipal User
{
get { return base.User as CommunityPrincipal; }
}
}
Then make your pages inherit from CommunityBasePage and you'll be able to get to all your properties from this.User.
Since you already storing the object in the HttpContext.User property all you really need to acheive you goal is a Static method that acheives your goal:-
public static class MySpecialContext
{
public static CommunityPrinciple Community
{
get
{
return (CommunityPrinciple)HttpContext.Current.User;
}
}
}
Now you can get the CommunityPrinciple as:-
var x = MySpecialContext.Community;
However it seems a lot of effort to got to avoid:-
var x = (CommunityPrinciple)Context.User;
An alternative would be an Extension method on HttpContext:-
public static class HttpContextExtensions
{
public static CommunityPrinciple GetCommunity(this HttpContext o)
{
return (CommunityPrinciple)o.User;
}
}
The use it:-
var x = Context.GetCommunity();
That's quite tidy but will require you to remember to include the namespace where the extensions class is defined in the using list in each file the needs it.
Edit:
Lets assume for the moment that you have some really good reason why even a cast performed inside called code as above is still unacceptable (BTW, I'd be really interested to understand what circumstance leads you to this conclusion).
Yet another alternative is a ThreadStatic field:-
public class MyModule : IHttpModule
{
[ThreadStatic]
private static CommunityPrinciple _threadCommunity;
public static CommunityPrinciple Community
{
get
{
return _threadCommunity;
}
}
// Place here your original module code but instead of (or as well as) assigning
// the Context.User store in _threadCommunity.
// Also at the appropriate point in the request lifecyle null the _threadCommunity
}
A field decorated with [ThreadStatic] will have one instance of storage per thread. Hence multiple threads can modify and read _threadCommunity but each will operate on their specific instance of the field.

Resources