How to mock DbUpdateConcurrencyException - entity-framework-core

I'm trying to mock function in my service to throw a DbUpdateConcurrencyException. My code only needs to check for an exception of type DbUpdateConcurrencyException and doesn't need to read the exception message or list of entries that the constructor asks for.
I want to set up the Mock by calling a parameter-less constructor for DbUpdateConcurrencyException, but that doesn't exist in EFCore.
var mockService = new Mock<IMyService>();
mockService.Setup(service => service.UpdateFooAsync(It.IsNotNull<Data.Foo>())).Throws(new DbUpdateConcurrencyException());
I've tried calling new DbUpdateConcurrencyException() with some parameters, but there's some checks that happen on the parameters that prevents me from doing this with null/empty data.
new DbUpdateConcurrencyException(null, null) gives:
Message: System.ArgumentNullException : Value cannot be null.
Parameter name: entries
new DbUpdateConcurrencyException("", new List<IUpdateEntry>()) gives:
Message: System.ArgumentException : The collection argument 'entries' must contain at least one element.
Is there a way in Moq that I can mock the DbUpdateConcurrencyException without having to go through the checks that the constructor has?

Based on docs you have shared in comments you should use ctor with two parameters. The trick is to provide not null string and not empty List<IUpdateEntry>, moq could help you with that, e.g.
new DbUpdateConcurrencyException(string.Empty, new List<IUpdateEntry>{Mock.Of<IUpdateEntry>()});

Related

mocking unique constraint check on dbContext

I have question regarding mocking dbContext for the purpose of unit testing.
In my below code i am mocking dbContext and DBSet entry using Moq library and then triggering Create method from service and in the end verifying SaveChanges was hit at least once successfully.
public void Create_Test_Item()
{
// creates a DbSet<TestItem>
var mockSet = new Mock<DbSet<TestItem>>();
mockSet.Setup(x => x.Add(It.IsAny<TestItem>())).Returns((TestItem testChildItem) => testChildItem);
// uses Moq to create a TestContext.
var mockContext = new Mock<TestContext>() { CallBase = true };
//wires it up to be returned from the context’s TestItem property.
mockContext.Setup(c => c.Set<TestItem>()).Returns(mockSet.Object);
mockContext.Setup(c => c.SaveChanges()).Returns(1);
//context is used to create a new TestsvcInstance<TestItem> which is then used to create a new TestItem
var svcInstance = new TestsvcInstance<TestItem>(mockContext.Object);
var TestItem = new TestItem
{
Name = "B01",
Code = "001",
ModuleId = new Guid("1F8B2910-C5D4-E611-80D0-000D3A80FCC4")
};
svcInstance.Create(TestItem);
// Finally, the test verifies that the svcInstance added a new TestItem and called SaveChanges on the context.
mockSet.Verify(m => m.Add(It.IsAny<TestItem>()), Times.Once());
mockContext.Verify(m => m.SaveChanges(), Times.Once());
}
I am trying to extend it further to add Unique check. Suppose if I try
to create TestItem with Code / Name that already saved in underlying
context, my mocking implementation should raise an error.
How I can achieve that through same mocking idea?
Your objective with tests should be to test your business logic, not EF. If you want to ensure that your database is set up with unique constraints use an integration test against a real database.
As far as unit tests are concerned, your business logic might be set up to avoid duplicate unique values. This means that given a scenario where your code would be considering duplicate values, your services/DbContext (if you have to go that deep) can be mocked to expect a validation call to assert that the desired value is not a duplicate.
So lets say I have a routine to validate that a user name for a new user is unique. That code goes to the Users DBSet, it will do some filtering or what-have you to determine if the user name is unique. I.e. DbContext.Users.Any(u=>u.UserName = userName);
if I were mocking a DBContext then I would mock the Users DBSet in that case to return a List<User> containing a single user with a name that matches the name I am testing with. My code under test should receive that User, fail its validation and my test should pass. I'd also assert my DBContext.SaveChanges does not get called in that scenario. So I tell the mock "Hey, give me something that I should figure out there is a duplicate user name, and make sure I don't call SaveChanges in this case."
To test how your code handles a duplicate ID constraint violation the mocked DbContext can be set up to Throw the exception expected in that case so that you can assert how your code handles that exception. You don't need to go through the trouble of setting up a mock to "detect" a duplicate constraint, just tell it "I'm going to give you one, so here is what you need to do."
So taking the above example say we want to test a race condition (someone else inserted that user just before, or some other developer mucked up my simple .Any() check with some extra filter that resulted in the duplicate user not being found. In this case I'd mock the Users DBSet to return an empty list for example, but then mock the SaveChanges call to throw an exception. (The same type as you'd receive inserting the duplicate record) From there you can assert the behaviour of your code under test. (Does it call a logging service, return back a different result? etc.)
With Moq that would look like:
mockDbContext.Setup(x=>x.SaveChanges()).Throws<SomeDbException>("Suitable message.");
Again though I'd say that while you can unit test this behaviour, the unit tests should be more about your business logic. (I.e. did it do a validation as expected?) An integration test against a real database or in-memory database can be set up to handle edge case scenarios. The difference between integration and unit tests are that integration tests would be run daily or a few times a day while unit tests with mocks are designed to be run repeatedly while you develop business logic where there is the risk of side effects as you go. The form a safety net around code/logic that is likely in flux. Constraints are relatively static behaviour.

A default DbContext context must exist, or a context factory must be provided

I'm getting the following error while performing "Bulk Insert" using EntityFramework extensions.
_indnCon.BulkInsert(_DataToTrans, operation => operation.IncludeGraph = true);
Exception occurs in the above line and here is the exception.
A default DbContext context must exist,
or a context factory must be provided (EntityFrameworkManager.ContextFactory).
This setting is required for some features like IncludeGraph.
Here I'm passing the Connection String to the DBContext manually.
using (InsightDataContext _indnCon = new InsightDataContext(_connectionString))
Can anyone help?
It seems that IncludeGraph feature needs to be able to create a new instance of your context, even if you already instantiated the context yourself in this scope. So, as the message says, you can try setting a default constructor for your context:
EntityFrameworkManager.ContextFactory = context => new CurrentContext(yourConnectionString);
The info comes from this post.

How do you make a null subject for BouncyCastle's X509v3CertificateBuilder?

We are switching from using X509V3CertificateGenerator to the new X509v3CertificateBuilder class. It insists on having an X500Name object for the subject, and throws an NPE if it's null. In our case, we want a null subject and will be using the SubjectAlternativeName (marked critical) as an alternative, which the specification allows.
How do we make an empty X500Name object to pass in to the builder's constructor?
Found it.
new X500Name(new RDN[0])

FakeItEasy mocked method won't return object, instead nullReferenceException

What I'm trying to do
I want a method, GetDirectoryInfo on a faked interface called fakeHiveReader to return a DirectoryInfo object.
I have to use the constructor to create the DirectoryInfo object I want to return, because that constructor calls a protected constructor for the parent class.
It's important that the method returns this specific DirectoryInfo object, so that I can check that later on, this object is used as a parameter for an important method.
The problem
The object is created fine, and I can see using breakpoints that the constructor is working, but then the last line throws an exception. If you run debug it stops on the line with a "NullReferenceException was unhandled by user code" pop-up. If you "View Detail" it says "System.NullReferenceException" and "Object reference not set to an instance of an object."
Any ideas would be hugely appreciated.
var fakeHiveReader = A.Fake<IHiveReader>();
DirectoryInfo di_1 = new DirectoryInfo(3, 4, "\\GeoWoods", "Gwood2", "Good", DateTimeOffset.UtcNow, true);
A.CallTo(() => fakeHiveReader.GetDirectoryInfo(#"\")).Returns(di_1);

How to get interpolated message in NHibernate.Validator

I'm trying to integrate NHibernate.Validator with ASP.NET MVC client side validations, and the only problem I found is that I simply can't convert the non-interpolated message to a human-readable one. I thought this would be an easy task, but turned out to be the hardest part of the client-side validation. The main problem is that because it's not server-side, I actually only need the validation attributes that are being used, and I don't actually have an instance or anything else at hand.
Here are some excerpts from what I've been already trying:
// Get the the default Message Interpolator from the Engine
IMessageInterpolator interp = _engine.Interpolator;
if (interp == null)
{
// It is null?? Oh, try to create a new one
interp = new NHibernate.Validator.Interpolator.DefaultMessageInterpolator();
}
// We need an instance of the object that needs to be validated, se we have to create one
object instance = Activator.CreateInstance(Metadata.ContainerType);
// we enumerate all attributes of the property. For example we have found a PatternAttribute
var a = attr as PatternAttribute;
// it seems that the default message interpolator doesn't work, unless initialized
if (interp is NHibernate.Validator.Interpolator.DefaultMessageInterpolator)
{
(interp as NHibernate.Validator.Interpolator.DefaultMessageInterpolator).Initialize(a);
}
// but even after it is initialized the following will throw a NullReferenceException, although all of the parameters are specified, and they are not null (except for the properties of the instance, which are all null, but this can't be changed)
var message = interp.Interpolate(new InterpolationInfo(Metadata.ContainerType, instance, PropertyName, a, interp, a.Message));
I know that the above is a fairly complex code for a seemingly simple question, but I'm still stuck without solution. Is there any way to get the interpolated string out of NHValidator?
Ok, so I know this is an old question, but I stumbled across this when trying to do the same thing, and it helped me get started - so I thought I would provide an answer.
I think the code in the question was on the right track but there are a couple of problems. The interpolator was not completely initialised with the ResourceManager and Culture details, and it doesn't seem to allow for the fact that you can only have one DefaultMessageInterpolator per validation attribute. Also, you don't need an instance of the object you are validating to get an interpolated message.
In the code in the question, where you are initialising the interpolator with the attribute value, you also need to initialise the interpolator with details of the ResourceManager to be used.
This can be done using the overloaded Initialize method on DefaultMessageInterpolator which has the following signature:
public void Initialize(ResourceManager messageBundle,
ResourceManager defaultMessageBundle,
CultureInfo culture)
The first parameter is a user-defined ResourceManager in case you want to use your own resource file for error messages, you can pass a null if you just want to use the default ResouceManager, the second parameter is the default ResourceManager - you can pass
new ResourceManager(
NHibernate.Validator.Cfg.Environment.BaseNameOfMessageResource,
Assembly.GetExecutingAssembly());
for this, the last parameter is the culture to use, (NHibernate.Validator comes with resource files with validation messages in several languages) - if you pass a null in to this it will just use CultureInfo.CurrentCulture
Lastly, you can only have one DefaultMessageInterpolator per attribute, so you will need to create a new DefaultMessageInterpolator for each validation attribute. You could make use of the DefaultMessageInterpolatorAggregator to handle this, or just roll your own.
I hope this helps someone.
Thanks for your help all--I'd upvote if I could. I just wanted to add that in addition to the first Initialize call on the DefaultMessageInterpolator that Stank illustrates, I also had to make a second different Initialize call to fully initialize it (I was getting some Null Reference Exceptions using only the first call). My code is as follows:
string interpolatedMessage = "";
DefaultMessageInterpolator interpolator = new DefaultMessageInterpolator();
interpolator.Initialize(null,
new ResourceManager(
NHibernate.Validator.Cfg.Environment.BaseNameOfMessageResource,
Assembly.Load("NHibernate.Validator")),
CultureInfo.CurrentCulture);
interpolator.Initialize(attribute as Attribute);
if (attribute is IValidator && attribute is IRuleArgs)
{
IValidator validator = attribute as IValidator;
IRuleArgs ruleArgs = attribute as IRuleArgs;
InterpolationInfo interpolationInfo = new InterpolationInfo(
validatableType,
null,
propertyName,
validator,
interpolator,
ruleArgs.Message);
interpolatedMessage = interpolator.Interpolate(interpolationInfo);
}

Categories