I have and interface IDatabaseInteraction:
public interface IDatabaseInteraction
{
void FillAppSection(List<AppSectionId> appSectionIds);
}
The definition for AppSectionId is:
public class AppSectionId
{
public string App;
public string Section;
public int Id;
}
I abstracted the database call into IDatabaseInteraction for the class under test.
The list comes in (in this testcase 1 item in appSectionIds) and is updated in the FillAppSection method, the Id gets filled.
I want to check the items App and Section values and secondly, I want to set the Id.
How do I do that using moq?
I would typically change that method to return a List<AppSectionId> as I think that is clearer. However, if you want to continue like this then you can use the Moq Callback method, something like this:
Mock<IDatabaseInteraction> databaseInteraction = new Mock<IDatabaseInteraction>();
databaseInteraction.Setup(x => x.FillAppSection(It.IsAny<List<AppSectionId>>())).Callback((List<AppSectionId> x) => x.Add(someObject));
Inside the Callback method you can then setup the List however you like.
Related
I have a quick question. Is it possible to use MongoDB with the OnDeserializing attribute or something like that?
MongoClient client { get; } = new MongoClient("mongodb://localhost:27017");
var Userscollection = db.GetCollection<UserModel>("Users");
var userfind = (await Userscollection.FindAsync(x => x.UserId == "UserId"));
var user = userfind.FirstOrDefault();
My UserModel class has a function with the OnDeserializing attribute but it doesn't fire on Find and fetching the item of the user.
[OnDeserializing]
void TestFunc(StreamingContext context)
{
}
Is there any way to fire it automatically or any similar method to detect in the constructor of the class if the class is creating by my codes or using the MongoDB serializer/deserializer?
OK, After poking a lot with attributes and lots of tries finally I found a solution for my case.
I commented above that creating 2 constructors doesn't work because settings values are going to be done after running constructors.
But, There's a workaround! BsonConstructor Attribute
create a simple constructor or with arguments for your own (if you need otherwise you can skip it)
Then create another constructor but using the BsonConstructor attribute like below.
[BsonConstructor()]
public Postmodel(ObjectId postid, ObjectId userid)
{
//Called by the BSon Serialize/Deserialize
}
But surely this constructor will not be what you need because all of the properties are null or having default values so you need to pass some argument too.
The sample below will give you the values of properties you need so you can do whatever you want in the constructor.
[BsonConstructor(nameof(Id), nameof(UserId))]
public Postmodel(ObjectId postid, ObjectId userid)
{
}
Id and UserId are two properties in my class.
You can also simply use
[BsonConstructor("Id", "UserId")]
instead, But be careful, Changing properties name or removing them in the development won't notify you to fix your values, so using nameof(PropertyName) is much safer.
I need to add a method to a model that given some parameters assigns a value to one of the model's fields.
public class ModelName: SomeModel<ModelName>, IModelName
{
[Field]
public string SomeField{ get; set; }
[Field]
public string FieldSetByMethod{ get; set; }
public new async Task MethodToSetField(string parameter)
{
var someClassInstance = new SomeExternalClass(parameter);
FieldSetByMethod = someClassInstance(parameter).method();
}
}
Now when I'm writing unit tests and I want to have a way of checking that this MethodToSetField was called. However, I can't really actually call the MethodToSetField method as creating SomeExternalClass is not desirable (e.g. because it creates unique ID).
I don't really have experience with neither C# nor Moq. How can I mock this function so it behaves more or less like this:
ModelNameInstance.Setup(c => c.MethodToSetField("Parameter")).Assigns(FieldSetByMethod,"DummyValue");
Or maybe I can somehow restructure the code / write tests in a way to imitate this behavior?
You could inject ISomeExternalClass into this class and then mock it, and test against the mock, or if you can't do that - inject ISomeExternalClassFactory into this class and then mock it. ISomeExternalClassFactory mock would return a mock of ISomeExternalClass that you could setup and test against.
In a view model's constructor I have a command declaration that calls a method:
OpenGroupCommand = new DelegateCommand(OnOpenGroupExecute);
And the method looks like:
private void OnOpenGroupExecute(object obj)
{
string groupName = (string)obj;
Application.Current.MainPage.Navigation.PushAsync(new GroupPage(groupName));
}
How can I test, that groupName is passed to another view model correctly? In another view model groupName parameter is sent to GroupName property on VM instance:
public class GroupPageViewModel : ViewModelBase, IGroupPageViewModel
{
private string _groupName;
public GroupPageViewModel(string groupName)
{
LoadGroupName(groupName);
}
public void LoadGroupName(string groupName)
{
GroupName = groupName;
}
public string GroupName
{
get
{
return _groupName;
}
set
{
_groupName = value;
OnPropertyChanged();
}
}
}
On debug all works fine, but how can I unit test it? Where can I read a bit about testing and mocking stuff like this, even with Moq framework?
I believe your question is actually about how to test navigation between pages.
In the implementation of method OnOpenGroupExecute, because you are using Xamarin forms stuff to implement the navigation, you have to refer Xamarin Forms assemblies in your test project which makes the unit test depend on Xamarin Forms.
As suggested in this document https://learn.microsoft.com/en-us/xamarin/xamarin-forms/enterprise-application-patterns/ , try to create an interface for navigation and navigate with viewmodel (more details on https://github.com/dotnet-architecture/eShopOnContainers)
And in your unit test project, implement a fake navigation service class like below and inject into the DI container:
public class FakeNavigationService : INavigationService //this interface is from MS eShopOnContainer project
{
private List<ViewModelBase> _viewModels = new List<ViewModel>();
public Task NavigateToAsync<TViewModel>() where TViewModel : ViewModelBase {
//create viewModel object from DI container
//var viewModel = ......
_viewModels.Add(viewModel);
}
public ViewModelBase CurrentPageViewModel {
get {
if (_viewModels.Count() < 1) {
return null;
}
return _viewModels[_viewModels.Count() - 1];
}
}
}
This is just a suggestion. If you have implemented most of features in your app, it takes time to change navigate-with-page to navigate-with-viewmodel.
Well, let's see what you have:
you have some code in a private method, unless you make that public you won't be able to test it directly, because you can't call it. I am not considering here any tricks that allow you to call private methods.
what does that method do? It is not clear at all, it receives an object, we don't know what's in it. You're converting it to string, but what if it is not a string? Can you convert that object to a string? who knows.
So we have a method, that we don't know what it does, we don't know what it receives as parameters, we can't call it directly, but we want to test it. This is not a good position to be in.
Step back a bit and ask yourself, what are you really trying to test?
You said : How can I test, that groupName is passed to another view model correctly?
what does "correctly" mean? You need to define what it means for that string to be correct. This will give a test scenario you can work with.
I expect to receive an object, which looks like A and I want to convert it to a string which looks like B. Forget about viewmodels for now, that's just unimportant noise.
You can change the method into a public one and you can test that for different types of input data, you're getting the right result. This is literally, working with an object and extract some stuff from it. When that method is correct, you can guarantee that the viewmodel will receive the right input and that is good enough from a unit testing point of view.
You can of course add more tests for various inputs, you can test for correct failure conditions etc.
I'm trying to show a list on my page using MyList:
public List<ResponseType> MyList(int param1, DateTime Date)
{
return db.spMyStoredProcedure(param1, param2).ExecuteTypedList<ResponseType>();
}
Which calls this stored procedure:
public StoredProcedure spMyStoredProcedure(int param1,DateTime Date){
StoredProcedure sp=new StoredProcedure("spMyStoredProcedure",this.Provider);
sp.Command.AddParameter("param1",LeadStatusID,DbType.Int32);
sp.Command.AddParameter("Date",Date,DbType.DateTime);
return sp;
}
Using this class:
public class ResponseType
{
public string 1 { get; set; }
public bool2 { get; set; }
public DateTime 3 { get; set; }
...etc.
}
ResponseType inherits another class, which in turn inherits another class.
Does the error message "Sequence contains more than one matching element" mean that there are multiple declarations for ResponseType (or the classes it inherits)? I only seem to have one of each declared, which is also where Visual Studio leads me to when I click "Go to Declaration".
I can execute the Stored Procedure fine in SQL Server with the same parameters I'm passing in, so I'm unsure why the list if failing to display.
I'm pretty sure that you are using SingleOrDefault or Single methods elsewhere. They succeed only when the collections contains 0 or 1 element. Why don't you try with FirstOrDefault which take always the first element (or defualt(type))?
Look at possible exception for SingleOrDefault:
ArgumentNullException --> source is null
InvalidOperationException --> The input sequence contains more than one element
Another possibility would be a First() call in your HttpPost method. Something like
[HttpPost]
public JsonResult Test(int Id)
{
var query = myDb.Responses
.Where(y => y.Id==Id).First();
return Json(new { Test= query.Name}, JsonRequestBehavior.AllowGet);
}
and if your Id doesn't exist that error can occur.
Sorry everyone, my problem was that I had defined a variable in ResponseType, and then again in a class it inherited.
Obviously there was no way for you to know that, as I hadn't included the inherited class.
Thanks anyway
I am new to using Mocks. But what are it's main purposes? I'm going to start by using Moq to test my application (and NUnit).
For example, I have code that does things like this:
My webpage code behind:
public partial class MyWebpage
{
protected string GetTitle(string myVar)
{
return dataLayer.GetTitle(myVar);
}
}
My data access layer:
public class DataLayer
{
public string GetTitle(string myVar)
{
// Create the query we want
string query = "SELECT title FROM MyTable " +
"WHERE var = #myVar";
//ENTER PARAMETERS IN HERE
// Now return the result to the view
return this.dataProvider.ExecuteMySelectQuery(
dr =>
{
//DELEGATE DATA READER PASSED IN AND TITLE GETS RETURNED
},
query,
parameters);
}
}
My data provider talks and interacts directly with the db:
public class DataProvider
{
public T ExecuteMySelectQuery<T>(Func<IDataReader, T> getMyResult, string selectQuery, Dictionary parameters)
{
//RUNS AND RETURNS THE QUERY
}
}
What's the best way to test all of this?
If you want to test the layers separately, you would need to create interfaces for your DataProvider and DataLayer classes that expose the methods that you want to Mock. Then you can use a mocking framework - NSubstitute is very good, less code to write to create the mocks - to mock out the calls to the dependent classes, leaving you to test the code within that specific unit
public interface IDataProvider
{
T ExecuteMySelectQuery<T>(Func<IDataReader, T> getMyResult, string selectQuery, Dictionary parameters);
}
public interface IDataLayer
{
string GetTitle(string myVar);
}
public class DataLayer
{
private IDataProvider dataProvider;
public DataLayer(IDataProvider dataProvider)
{
this.dataProvider = dataProvider;
}
}
Then, in your test code, you create mocks instead of real objects and pass those into the constructor when you instantiate your test objects. To test the DataLayer:
[Test]
public void WhenRetievingTitleFromDataStore_ThenDataLayerReturnsTitle()
{
var title = "Title";
var dataProviderMock = new Mock<IDataProvider>(MockBehavior.Strict);
dataProviderMock.Setup(x => x.ExecuteMySelectQuery(<parameters>)).Returns(title);
var dataLayer = new DataLayer(dataProviderMock.Object);
Assert.That(dataLayer.GetTitle(It.IsAny<string>(), Is.EqualTo(title));
}
The only thing that can go wrong with that is the DB call (the query or the returned result is of wrong data types). That can't be mocked. You need to do integration tests and not unit tests.
Typically you only mock to be able to test logic in the code. You should for instance test so that the data mapper (this.dataProvider.ExecuteMySelectQuery) works as defined. but that's of the scope of the code in question.
Update
So you got the following classes:
public class DataLayer
{
public string GetTitle(string myVar)
{
// Create the query we want
string query = "SELECT title FROM MyTable " +
"WHERE var = #myVar";
//ENTER PARAMETERS IN HERE
// Now return the result to the view
return this.dataProvider.ExecuteMySelectQuery(
dr =>
{
//DELEGATE DATA READER PASSED IN AND TITLE GETS RETURNED
},
query,
parameters);
}
}
public class DataProvider
{
public T ExecuteMySelectQuery<T>(Func<IDataReader, T> getMyResult, string selectQuery, Dictionary parameters)
{
//RUNS AND RETURNS THE QUERY
}
}
If we examine the ExecuteMySelectQuery we can see that the DataLayer class is dependent of how the types that the database returns since the DataProvider just ease the query execution. One could say that it's an addon on top of ADO.NET.
That also means that you can never guarantee that DataLayer return what's promised without involving the database. Let's for instance assume that the table in the database has a column called title but someone managed to use the int data type instead.
The things that can go wrong are
The query is incorrect
The schema in the database is incorrect (wrong column names, data types etc)
The mapping
None of those errors can be detected nor tested with the help of a mock.
If you on the other hand use the DataLayer clas in another class you can of course mock it. Because the DataLayer class itself is a complete abstraction. That means that the callers of the class doesn't have to be aware of anything beneath it. Hence mocking is perfectly fine.