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.
Related
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 have a unit test project build over an older version of a class. Let's say I'm working on a new version which adds a field to the class, like below.
public class Customer
{
public string FirstName { get;set; }
}
public class Customer2
{
public string FirstName { get;set; }
public string LastName { get;set; }
}
In my unit test, do I just create a new Customer2 class with the new field in it and test against that class?
Unit tests exist to test logic not classes. So you shouldn't create a unit test just because you add 1 property to a class. If you just added a new field to the class, your existent unit tests will be affected by that, and if something breaks you will see that affecting the result of the unit test. If because of the new field you needed to create new services/components/methods/etc... in this case you should create unit tests for those new things to prove that your logic is well implemented.
Edit
Case you create properties with logic inside getters and setters, then you should test that, otherwise there's no need to create tests for POCO objects
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.
I am using Moq for unit testing in C# and want to put some fake data in the following class.
public class UserResponse
{
public IEnumerable<usertab> userlist{get;set;}
public string Name {get;set;}
public string state {get;set;}
public string country {get;set}
}
public class usertab
{
public string tname {get;set;}
public string fname {get;set;}
}
Please correct me if below code is correct to fake a class wtih IEnumerable
var userdata = new usertab[]{
new usertab{tName="Employee",fName="abc"},
new usertab{tName="Employee",fName="xyz"},
};
Well you're not "faking" it at all - you're just using an array as the implementation. There's nothing wrong with doing that - personally I like using real code within tests, so long as:
You have confidence in the other code you're relying on (arrays in this case) either because it's supplied from a trustworthy source (the BCL in this case) or you have tests
You don't need to perform interaction testing - for example, if you want to check that you only iterate over the collection once, arrays won't help you do that
The real code doesn't slow down the testing (e.g. by making network connections, requiring a database etc). Not a problem with arrays.
I'm trying to learn how to do Unit testing with C# and Moq, and I've built a little test situation. Given this code:
public interface IUser
{
int CalculateAge();
DateTime DateOfBirth { get; set; }
string Name { get; set; }
}
public class User : IUser
{
public DateTime DateOfBirth { get; set; }
string Name { get; set; }
public int CalculateAge()
{
return DateTime.Now.Year - DateOfBirth.Year;
}
}
I want to test the method CalculateAge(). To do this, I thought I should try giving a default value to the DateOfBirth property by doing this in my test method:
var userMock = new Mock<IUser>();
userMock.SetupProperty(u => u.DateOfBirth, new DateTime(1990, 3, 25)); //Is this supposed to give a default value for the property DateOfBirth ?
Assert.AreEqual(22, userMock.Object.CalculateAge());
But when It comes to the assertion, the value of CalculateAge() equals 0, although DateOfBirth equals new DateTime(1990, 3, 25).
I know this may look like a silly example, but whatever... I thought I could use mocking to give values to not-yet-developed method/properties in my objects, so the testing of a method wouldn't depend on another component of my class, or even setting up a default context for my object (hence the name of the user here...) Am I approaching this problem the wrong way?
Thanks.
Yes, you approaching it wrong, but don't worry, I'll explain why. First hint would be
you can completely remove your User class and everything will be the
same.
When you are doing:
var userMock = new Mock<IUser>();
You just creating a fake\mock object of that interface, that has nothing to do with your initial User class, so it doesn't have any implementation of CalculateAge method, except of fake one that just silly returns 0. That's why you are getting 0 in your assert statement.
So, you were saying:
thought I could use mocking to give values to not-yet-developed
method/properties in my objects, so the testing of a method wouldn't
depend on another component of my class
You could, let's say you will have some consumer of your IUser, lets say like the following:
class ConsumerOfIUser
{
public int Consume(IUser user)
{
return user.CalculateAge() + 10;
}
}
in that case mocking of IUser will make total sense, since you want to test how your ConsumerOfIUser behaves when IUser.CalculateAge() returns 10. You would do the following:
var userMock = new Mock<IUser>();
userMock.Setup(u => u.CalculateAge()).Returns(10);
var consumer = new ConsumerOfIUser();
var result = consumer.Consume(userMock);
Assert.AreEqual(result, 20); //should be true
It depends on what your trying to test. In this case, you have mocked out the User object, so there is no point in testing anything inside this class as you are replacing it with a mock object. If you want to test the User object then you shouldn't mock it out.
Mocks are used to replace dependant objects that you don't want to test. For example, if you had a Name object instead of a string (e.g contains first name, surname, title etc..) but you didn't want to test the Name object, just the User object, you would create a mock of the Name object to be used when constructing the User object.