The requirement here is to write test cases for the Opc Ua NodeManager and it uses NodeId from Opc.Ua class.
Methods/properties in NodeId class cannot be moq because they are Non-Overridable methods and have ony get in them.
So I created a wrapper on top of NodeId class and tried to Moq that class. It works fine but now I have 2 methods/Properties
public class NodeIdTestClass : NodeId
{
public NodeIdTestClass()
{
}
public new virtual object Identifier
{
get => base.Identifier;
}
public new virtual ushort NamespaceIndex
{
get => base.NamespaceIndex;
}
public new virtual bool IsNullNodeId
{
get => base.IsNullNodeId;
}
}
//Arrange
var nodeIdMock = new Mock<NodeIdTestClass>() { CallBase = true };
nodeIdMock.Setup(x => x.Identifier).Returns(nodeIdMock.Object.Identifier);
nodeIdMock.Setup(x => x.NamespaceIndex).Returns(1);
nodeIdMock.Setup(x => x.IsNullNodeId).Returns(false);
_nodemanager.SetNamespaces(new string[] { "0", "1", "2" });
//Act
var result = _nodemanager.GetManagerHandle(nodeIdMock.Object);
The problem :
Is there something wrong with code?
Do you need a mock?
Wouldn't this be enough?
var nodeId = new NodeId(value: 17, namespaceIndex: 1);
var result = _nodemanager.GetManagerHandle(nodeId);
Related
I have read the document https://gist.github.com/netoisc/5d456850d79f246685fee23be2469155
which well know how to mock elasticsearch query
But I have a case which return result have innerhits
Documents = searchResult.Hits.Select(
h => {
if (h.InnerHits.TryGetValue("books", out var data)) {
ht.Source.Books = data!.Documents<book>();
}
ht.Source.Books = ht.Source.Books.Where(k=>k.country=="US");
return h.Source;
})
From my mock test
I have do this
var innerHitResult = new Mock<InnerHitsResult>();
innerHitResult.SetupGet(s => s.Documents<book>()).Returns(new List<book>());
var innerHitDictionary = new Dictionary<string, InnerHitsResult> {
{
"books", innerHitResult.Object
}
};
I've got the error on innerHitResult.SetupGet , which error say :
System.ArgumentException: Expression is not a property access: s => s.Documents<book>()
Even I use innerHitResult.Setup is not working
Can I know how to do mock for inner hit ?
In the other simple example
if I have a class :
public class BlogSearchResult
{
public InnerMetaData Hits { get; set; }
public IEnumerable<T> Document<T>() where T : class => Hits.Documents<T>();
}
I want to mock BlogSearchResult which want to do
var blogs = fixture.CreateMany<Blog>();
var blogSearch = new Mock<BlogSearchResult>();
blogSearch.SetupGet(s => s.Document<Blog>()).Returns(blogs);
or
blogSearch.Setup(s => s.Document<Blog>()).Returns(blogs);
They are all return error, is that possible ?
Is there a way to disable completely (for all classes) the discriminator ("_t") fields from being added to the bson documents?
I am referring to: mongo-csharp-driver/polymorphism
Let's say we have a Square and Rectangle that inherit from Shape.
public abstract class Shape
{
public ObjectId Id { get; set; }
}
public sealed class Square : Shape
{
public int Size { get; set; }
}
public sealed class Rectangle : Shape
{
public int Width { get; set; }
public int Height { get; set; }
}
Like you said if we run the following code.
var client = new MongoClient();
var db = client.GetDatabase("test");
var shapes = db.GetCollection<Shape>("shapes");
await shapes.InsertManyAsync(new Shape[]
{
new Square{Size = 10},
new Rectangle{Height = 5, Width = 4}
});
We'll get the following inserted into MongoDB
db.shapes.find()
{ "_id" : ObjectId("5f4e2affc23dde5a501bdf0b"), "_t" : "Square", "Size" : 10 }
{ "_id" : ObjectId("5f4e2affc23dde5a501bdf0c"), "_t" : "Rectangle", "Width" : 4, "Height" : 5 }
Initially, I thought we'd be able to set the DiscriminatorIsRequired flag on the BsonClassMap and wrap that in a convention, however, from trying this it seems to fail due to the following bit of logic in the MongoDB C# Driver.
private bool ShouldSerializeDiscriminator(Type nominalType)
{
return (nominalType != _classMap.ClassType || _classMap.DiscriminatorIsRequired || _classMap.HasRootClass) && !_classMap.IsAnonymous;
}
https://github.com/mongodb/mongo-csharp-driver/blob/9e567e23615c8bb5c7ac1489427c2d15b2124522/src/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs#L722
So because there's no way for us to tell the serializer we don't want to include a discriminator we'll have to give it a convention instead that does nothing.
If we create an IDiscriminatorConvention that pretty much does nothing and returns back null for the discriminator then the driver won't add this to the document.
public class NullDiscriminatorConvention : IDiscriminatorConvention
{
public static NullDiscriminatorConvention Instance { get; }
= new NullDiscriminatorConvention();
public Type GetActualType(IBsonReader bsonReader, Type nominalType)
=> nominalType;
public BsonValue GetDiscriminator(Type nominalType, Type actualType)
=> null;
public string ElementName { get; } = null;
}
This discriminator convention then needs to be registered against each type.
BsonSerializer.RegisterDiscriminatorConvention(typeof(Square), NullDiscriminatorConvention.Instance);
BsonSerializer.RegisterDiscriminatorConvention(typeof(Rectangle), NullDiscriminatorConvention.Instance);
Alternately if we want it on all types you could do a little bit of reflection.
var shapeTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(domainAssembly => domainAssembly.GetTypes(),
(domainAssembly, assemblyType) => new {domainAssembly, assemblyType})
.Where(t => #t.assemblyType.IsSubclassOf(typeof(Shape)))
.Select(t => #t.assemblyType).ToArray();
foreach (var shapeType in shapeTypes)
{
BsonSerializer.RegisterDiscriminatorConvention(shapeType, NullDiscriminatorConvention.Instance);
}
Now if we re-run our code.
var shapeTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(domainAssembly => domainAssembly.GetTypes(),
(domainAssembly, assemblyType) => new {domainAssembly, assemblyType})
.Where(t => #t.assemblyType.IsSubclassOf(typeof(Shape)))
.Select(t => #t.assemblyType).ToArray();
foreach (var shapeType in shapeTypes)
{
BsonSerializer.RegisterDiscriminatorConvention(shapeType, NullDiscriminatorConvention.Instance);
}
var client = new MongoClient();
var db = client.GetDatabase("test");
var shapes = db.GetCollection<Shape>("shapes");
await shapes.InsertManyAsync(new Shape[]
{
new Square{Size = 10},
new Rectangle{Height = 5, Width = 4}
});
we'll get our expected output.
db.shapes.find()
{ "_id" : ObjectId("5f4e2d63ed12d7c5d3638d36"), "Size" : 10 }
{ "_id" : ObjectId("5f4e2d63ed12d7c5d3638d37"), "Width" : 4, "Height" : 5 }
One option is using Newtonsoft bson serializer (Newtonsoft.Json.Bson) which gives a lot of serialization options.
It isn't efficient since you need to write the bson to a stream and then read it from there with MongoDb reader but it provides lots of customization option.
Example code:
class BsonDocBuilder
{
private readonly MemoryStream _memStream = new MemoryStream();
private readonly JsonSerializerSettings _serializeSettings = new JsonSerializerSettings();
private readonly JsonSerializer _jsonSerializer;
public BsonDocBuilder()
{
_jsonSerializer = JsonSerializer.Create(_serializeSettings);
}
public BsonDocument ToBson<T>(T value)
{
BsonDocument bd;
try
{
using (BsonDataWriter dataWriter = new BsonDataWriter(_memStream))
{
dataWriter.CloseOutput = false;
_jsonSerializer.Serialize(dataWriter, value);
}
bd= BsonSerializer.Deserialize<BsonDocument>(_memStream.ToArray());
}
finally
{
_memStream.SetLength(0);
}
return bd;
}
}
I have a property like the following:
RuleFor(c => c.foo).GreaterThan(0);
In the docs of fluent validation, they specify that if I cannot make use of "ShouldHaveValidationErrorFor" method, I could make some assertions with the "Validate" method, but I can't wrap my head around this
All I got is something along this lines:
public void Should_Have_Error_When_Foo_Isnt_Greater_Than_Zero()
{
var bar = new Bar
{
Foo = -1
};
var result = validator.TestValidate(bar);
//Assert.True(bar.Foo > 0, ??)
}
You can do it both ways.
Based on the information provided, assuming your Bar class and BarValidator look something like the following:
public class Bar
{
public int Foo { get; set; }
}
public class BarValidator : AbstractValidator<Bar>
{
public BarValidator()
{
RuleFor(c => c.Foo).GreaterThan(0);
}
}
...I'd normally just do it against the validator, it's neater. The following code tests both a pass and fail state.
public class BarValidatorTests
{
[Test]
public void Foo_Zero_HasValidationError()
{
var validator = new BarValidator();
var dto = new Bar { Foo = 0 };
validator.ShouldHaveValidationErrorFor(x => x.Foo, dto);
}
[Test]
public void Foo_One_DoesNotHaveValidationError()
{
var validator = new BarValidator();
var dto = new Bar { Foo = 1 };
validator.ShouldNotHaveValidationErrorFor(x => x.Foo, dto);
}
}
If you do want to use the TestValidate method, and there are cases where you do want to do it (I use it when my class has a collection of child objects, and I want to test a validation rule on a specific child object), then then following is functionally equivalent to the previous:
public class BarValidatorTestsUsingTestValidate
{
[Test]
public void Foo_Zero_HasValidationError()
{
var validator = new BarValidator();
var dto = new Bar { Foo = 0 };
var validationResults = validator.TestValidate(dto);
validationResults.ShouldHaveValidationErrorFor(x => x.Foo);
}
[Test]
public void Foo_One_DoesNotHaveValidationError()
{
var validator = new BarValidator();
var dto = new Bar { Foo = 1 };
var validationResults = validator.TestValidate(dto);
validationResults.ShouldNotHaveValidationErrorFor(x => x.Foo);
}
}
I have done fair bit research and tried all sorts of different ways of getting the Test to pass but now i need some help.
I am trying to test the following repository method:
public class PortalsRepository : BaseRepository<PortalDomainRole>, IPortalsRepository
{
public PortalsRepository(IAuthDbContext context) : base(context)
{
}
public IEnumerable<PortalRole> GetRoles(string domainName)
{
return Set.Include(x => x.PortalDomain)
.Include(x => x.PortalRole)
.Where(x => x.PortalDomain.Name.ToLower() == domainName)
.Select(x => x.PortalRole)
.ToList();
}
}
The Context looks like:
public interface IAuthDbContext : IDbContextBase
{
}
public interface IDbContextBase
{
IDbSet<T> Set<T>() where T : class;
IEnumerable<DbValidationError> GetEntityValidationErrors();
int SaveChanges();
Task<int> SaveChangesAsync();
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
}
My Unit Test Set-up Looks like:
protected override void GivenThat()
{
var mockRolesSet = GetMockDbSet(PortalRoles().AsQueryable());
mockRolesSet.Setup(x => x.Include("PortalRole")).Returns(mockRolesSet.Object);
var mockDomainsSet = GetMockDbSet(PortalDomains().AsQueryable());
mockDomainsSet.Setup(x => x.Include("PortalDomain")).Returns(mockDomainsSet.Object);
var mockPortalDomanRolesSet = GetMockDbSet(PortalDomainRoles().AsQueryable());
mockPortalDomanRolesSet.Setup(x => x.Include("PortalRole")).Returns(mockPortalDomanRolesSet.Object);
mockPortalDomanRolesSet.Setup(x => x.Include("PortalDomain")).Returns(mockPortalDomanRolesSet.Object);
var customDbContextMock = new Mock<IAuthDbContext>();
customDbContextMock.Setup(x => x.Set<PortalRole>()).Returns(mockRolesSet.Object);
customDbContextMock.Setup(x => x.Set<PortalDomain>()).Returns(mockDomainsSet.Object);
customDbContextMock.Setup(x => x.Set<PortalDomainRole>()).Returns(mockPortalDomanRolesSet.Object);
ClassUnderTest = new PortalsRepository(customDbContextMock.Object);
}
My Unit Test Supporting Methods:
public List<PortalDomainRole> PortalDomainRoles()
{
var data = new List<PortalDomainRole>
{
new PortalDomainRole { PortalRoleId = 2, PortalDomainId = 1},
new PortalDomainRole { PortalRoleId = 1, PortalDomainId = 2},
new PortalDomainRole { PortalRoleId = 2, PortalDomainId = 2}
};
return data;
}
public List<PortalDomain> PortalDomains()
{
var data = new List<PortalDomain>
{
new PortalDomain { Name = "google.co.uk", PortalDomainId = 1 },
new PortalDomain { Name = "bbc.com", PortalDomainId = 2 }
};
return data;
}
public List<PortalRole> PortalRoles()
{
var data = new List<PortalRole>
{
new PortalRole {Name = "New Products", PortalRoleId = 1},
new PortalRole {Name = "Classic Products", PortalRoleId = 2}
};
return data;
}
When the unit test executes the method in question, i get:
System.NullReferenceException : Object reference not set to an instance of an object.
Most likely it does not know how to handle the nested include statements - i have followed many online questions and tutorials and now i am stuck.
My answer is probably a bit controversial, but in my experience, the best way to test your repository layer (or whatever you call the code that does the actual data access), is by having it actually call the database during testing.
When you are writing your unit test, you are assuming that Entity Framework works in a specific way. But sometimes it works in different ways than you expect, and thus a test may pass, even though the code doesn't work correctly.
Take this example, that illustrates the problem (the last EF version I worked with was version 4, but I assume that my statement is still true for EF6)
public class Foo {
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public bool Active {
get { return StartDate < DateTime.Now && EndDate > DateTime.Now }
}
}
public class FooRepository {
public IEnumerable<Foo> ActiveFoos { get { return DataContext.Foos.Where(x => x.Active) } }
}
Testing this FooRepository against a mocked data access will pass, but executing against a real database will throw an exception. That is because EF will try to create an SQL clause for the Where(x => x.Active), but because Active is not a field in the database, EF will have no idea how to translate the query to SQL.
So your unit test provides a false positive. Executing the tests against the database will make it fail, as it should.
I have the following code:
var connector = new Mock<IConector>();
connector
.Setup(cn => cn.listar("FetchEstandar", new Estandar(), new {Id = 1}))
.Returns(new List<Estandar>{ new Estandar {Id = 1} });
var entidad = connector.Object
.listar("FetchEstandar", new Estandar(), new {Id = 1});
when I call listar on the connector Object, I get an "Expression Cannot Contain an Anonymouse Type" error. I've tried with rhino mocks and moq.
Is there any way I can mock this method? am I doing something wrong? alternatively, I could ignore this parameter but I don't know how. I really just need to test the value of the first parameter and ignorearguments works but I have no idea whether or how I can get this value if I use it
I do not know if this is the only way to match an anonymous object but it can be done using It.Is<>() and reflection
public class Estandar {
public int Id { get; set; }
}
public interface IConector {
IEnumerable<Estandar> listar(string name, Estandar estandar, object key);
}
[TestMethod]
public void CheckAnonymous() {
var connector = new Mock<IConector>();
connector.Setup(cn => cn.listar("FetchEstandar",
It.IsAny<Estandar>(),
It.Is<object>(it => MatchKey(it, 1))))
.Returns(new List<Estandar> { new Estandar { Id = 1 } });
var entidad = connector.Object.listar("FetchEstandar", new Estandar(), new { Id = 1 });
Assert.AreEqual(1, entidad.Count());
}
public static bool MatchKey(object key, int soughtId) {
var ret = false;
var prop = key.GetType().GetProperty("Id");
if (prop != null) {
var id = (int)prop.GetValue(key, null);
ret = id == soughtId;
}
return ret;
}