I'm coding an application using CQRS. I have my commands and my commandHandler. I do tests my commands handlers. But...should you recommend testing commands? What's the best strategy? Should I test all validation possibilities? How do you guys do?
using System;
using Flunt.Notifications;
using Flunt.Validations;
using Todo.Domain.Commands.Contracts;
namespace Todo.Domain.Commands
{
public class CreateTodoCommand : Notifiable, ICommand
{
public CreateTodoCommand() { }
public CreateTodoCommand(string title, string user, DateTime date)
{
Title = title;
User = user;
Date = date;
}
public string Title { get; set; }
public string User { get; set; }
public DateTime Date { get; set; }
public void Validate()
{
AddNotifications(
new Contract()
.Requires()
.HasMinLen(Title, 3, "Title", "Please, describe better your task!")
.HasMinLen(User, 6, "User", "Invalid User!")
);
}
}
}
should you recommend testing commands?
How often do you change commands?
How likely are you to introduce a mistake when changing a command?
How expensive is it for this mistake to escape into a release?
How expensive is it to test?
Commands are out near the input boundary, and one of the common problems that we have near the input boundary is parsing some general purpose data structure to ensure that it satisfies our bespoke constraints.
Does parsing need to be tested? Well, it is logic (more than one possible outcome), so it is certainly a candidate to consider.
Chances are: you don't have particularly specific answers to the questions above. In that case, I would err on the side of introducing tests: because the tests give you a way to collect data, which over time will improve your answers.
Related
Using Sitecore 10.2 and Glass Mapper 5.8.180
After upgrade from Sitecore 8.2 and switching to above mentioned version of Glass Mapper our code stopped loading collection references. I am aware that in Glass Mapper now the lazy loading is turned on by default and I want to keep this setting.
Problem is with follows:
Having
[SitecoreType(TemplateId = "{...}", AutoMap = true)]
public interface IStatementContainer
{
IEnumerable<Statement> Statements { get; set; }
}
public class StatementContainer : IStatementContainer
{
public virtual IEnumerable<Statement> Statements { get; set; }
}
The following code
_mvcContext.SitecoreService.GetItem<StatementContainer>(datasource)
does not work properly. The Statements are empty.
For following code
_mvcContext.SitecoreService.GetItem<IStatementContainer>(datasource)
the Statements are being loaded properly.
Could you explain me the difference in behavior?
Our legacy code contains a lot of usages of concrete types rather than interfaces, changing all of them would be difficult.
I did some research about this problem, but NOTHING comes close to MY difficulty.
Here's my SQL :
CREATE TABLE [dbo].[Departement] (
[IdDepartement] INT IDENTITY (1, 1) NOT NULL,
[Description] NVARCHAR (255) NOT NULL,
[IsActif] BIT NULL,
PRIMARY KEY CLUSTERED ([IdDepartement] ASC)
);
As you can see, IsActif IS null.
Here's part of my Departement.cs :
public Nullable<bool> IsActif { get; set; }
Once again, everything is normally nullable.
Here's part of my Metadata (for not loosing the annotations when the database is updated) :
[UIHint("YesNo")]
public Nullable<bool> IsActif { get; set; }
Still, a nullable force of the nature, without [Required]! (If someone wonders what is a UIHint: it is connected to a DisplayTemplate and it just presents nicely my bit value).
Just for the curious ones, because I feel my question will not be complete if I do not put everything in here. Here's my UiHint:
#model Nullable<bool>
#if (Model.HasValue)
{
if (Model.Value)
{ <text>Oui</text> }
else
{ <text>Non</text> }
}
else
{ <text>Indéfini</text> }
It clearly states if Model Has Value ON Nullable!!!
But this is what I get when a try to Create a new department:
which means 'the field IsActif is required.'
Someone has an idea what is going on? All my other nullable booleans work perfectly. Is there's a place I forgot to look? What's the next step?
If someone have an idea, please let me know. I did pet my computer to make this work, but I am about to eat it now.
Thanks in advance.
Edit
Mea Culpa: Oooooooooh, I so want to die. I just realised I was using a ViewModel and I should check there. And there it was, the culprit looking at me with a devilish snigger. I am sorry for this newbie mistake and for my punishment, I will close this question and mark it as answered and leave it here for everybody to laugh at me and just in case another newbie have the same problem. I still do not understand why my others nullable boolean worked, while they were in the same situation, though...
Just go see my Edit. I am too shameful to repeat it here. Thanks anyway to those who took their time to add comments, specially Jasen.
In big:
EmployeViewModel before:
public bool IsActif { get; set; }
EmployeViewModel after:
public Nullable<bool> IsActif { get; set; }
Now I just have to hide myself under a carpet.
Is there a simple way to specify a list of possible values for the parameter orderBy? Not one by one please, otherwise I would not be making the question. I want to specify that orderby makes sense only if it is chosen from a predetermined list. Suppose the list is very large...still not random. This cannot be that hard...no single example of such a simple task.
[Test, AutoData]
public override void IndexReturnsView(int? pageIndex, int? pageSize, string orderBy, bool? desc)
{
.....
}
EDIT:
All I want is to read the possible values from a list as I would do with the ValueSource attribute. However, it seems not to work with AutoFixture. If I specified e.g. [ValueSource("GetOrderByColumnNames")] my test does not work anymore. I have no idea of what I am doing wrong. Unfortunately AutoFixture lacks useful documentation and the examples are very basic. Is there a working example of this scenario that I can use to guide myself here?
This has to be a very common situation, however I have been looking for days with no luck :(.
Appreciated!
If I understand the question correctly, the problem is that the orderBy value should be randomly selected from a list of predefined values, but that list might be too large to use with [InlineAutoData].
The easiest way to do this that I can think of is to introduce a helper type. This might actually be a valuable addition to the application code itself, as it makes the role of various values more explicit, but if not, you can always add the wrapper type to the test code base.
Something like this is the minimum you'll need:
public class OrderCriterion
{
public OrderCriterion(string value)
{
Value = value;
}
public string Value { get; }
}
If we also imagine that this class exposes a list of ValidValues, you can implement an AutoFixture Customization using the ElementsBuilder class:
public class OrderCriterionCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(
new ElementsBuilder<OrderCriterion>(OrderCriterion.ValidValues));
}
}
Then you create a data source attribute for your test code base:
public class TestConventionsAttribute : AutoDataAttribute
{
public TestConventionsAttribute() : base(
() => new Fixture().Customize(new OrderCriterionCustomization()))
{
}
}
This enables you to write a test like this, which passes:
[Theory, TestConventions]
public void IndexReturnsView(
int? pageIndex,
int? pageSize,
OrderCriterion orderBy,
bool? desc)
{
Assert.Contains(orderBy.Value, OrderCriterion.ValidValues.Select(x => x.Value));
}
Notice that instead of declaring the orderBy parameter as a string, you declare it as an OrderCriterion, which means that AutoFixture will be detect its presence, and the Customization then kicks in.
See also https://stackoverflow.com/a/48903199/126014
I'm developing a Login View in MVC5.
I would like to set at the ViewModel level a DataAnnotation to state the the field does NOT accept empty spaces.
Is there a Data Annotation in MVC (something like [NoSpaces] that can be used to NOT allow a string field to contain "spaces" ?
How about this:
[RegularExpression(#"^\S*$", ErrorMessage = "No white space allowed")]
Well, the simplest but robust thing I can think of is to look at how existing code works, or how existing data annotation work.
For example, let's look at the System.ComponentModel.DataAnnotations.StringLengthAttribute class.
Here's the definition only (just to keep short):
namespace System.ComponentModel.DataAnnotations
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
public class StringLengthAttribute : ValidationAttribute
{
public StringLengthAttribute(int maximumLength);
public int MinimumLength { get; set; }
public override string FormatErrorMessage(string name);
public override bool IsValid(object value);
}
}
So I would simply copy the original implementation source code from GitHub and customize it to my needs. For example, to obtain a signature like this (if I understood correctly and this is what you wanted):
public StringLengthAttribute(int maximumLength, int minLength = 0, allowEmptySpaces = true);
For more in-depth info, I would also read the Microsoft docs on the ValidationAttribute class, which is your base class for custom validation data annotations.
EDIT:
I would NOT rely on Regular Expressions to validate data in cases where I just need to exclude empty strings or strings containing only white space(s), because Regular Expressions are very expensive to process (and require a lot of memory allocation, because of an expression compiler, a state machine, etc.).
If this is convenient for anyone, I got pass this issue by doing this on the client:
//trim each form input
var $form = $("#myForm");
$form.find("input:text").each(function(){
var $self= $(this);
$self.va($self.val().trim());
});
//then validate before submit
if($form.valid()){ $form.submit(); }
// on the server ModelState.Isvalid does verify each item with [Required] and won't accept only white spaces from an input (but this means additional roundtrip to server and it's not always convenient)
Ok, I wrote this question up earlier today but I decided to delete it because I thought the question wasn't worded very well. I decided to wait until I had more time to compose it at home :).
I am just getting started with IOC/DI. I have done some research on which framework to use and decided to give StructureMap a spin. The following is the first tutorial I used:
http://dimecasts.net/Casts/CastDetails/39 by Derik Whittaker.
Anyways, I got everything working like a dream with EVERYTHING is hosted in the same project.
Here is my sample code:
[PluginFamily("SMTest",IsSingleton=true)]
public interface IVehicle
{
byte TopSpeed {set;get;}
byte MPG { set; get; }
}
[Pluggable("SMTest")]
public class Car : IVehicle
{
private byte mTopSpeed;
private byte mMPG;
#region IVehicle Members
byte IVehicle.TopSpeed
{
get
{
return mTopSpeed;
}
set
{
mTopSpeed = value;
}
}
public interface IConsumer
{
IVehicle Car { get; set; }
}
[Pluggable("SMTest")]
public class Consumer : StructureMapBasic.IConsumer
{
private IVehicle mCar;
public Consumer(IVehicle lcar)
{
Car = lcar;
}
public IVehicle Car { set; get; }
byte IVehicle.MPG
{
get
{
return mMPG;
}
set
{
mMPG = value;
}
}
#endregion
}
So anyways if i create the project above into a command line program and do the following:
var consumer = ObjectFactory.GetInstance<IConsumer>();
It works perfectly. No problems at all. When i create a seperate project in the solution and then change the project above to a DLL. I get the following error:
Test method StructureMapBasic.ConsumerTest.ConsumerConstructorTest
threw exception: StructureMap.StructureMapException: StructureMap
Exception Code: 202 No Default Instance defined for PluginFamily
StructureMapBasic.IConsumer, StructureMapBasic, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null.
At first i thought maybe the StructureMap.Config file didn't get into the new projects bin folder but that wasn't the case. It was there. Everythign compiles just fine this problem happens at runtime. I'm sure the solution is very easy but for the life of me i can't figure out whats going wrong. Any help would be MUCH appreciated.
Thanks,
Ncage
I took me all friggn day to figure this out. At first i thought i was just being an idiot and i was missing something stupid. Well i was not. I thought it was related to different projects but it was not. I created a new console application that consumed my StructureMapped DLL (If just coined a term ;) ). Anyways, after trying to spend all day on this problem i FINALLY found a post that described the problem. its a freakn bug in MSTest (my project i was having problems with was created in MSTest). Xunit here i come. Here is a post that describes the issue from the same guy who created the tutorial video:
http://devlicio.us/blogs/derik_whittaker/archive/2008/07/23/mstest-why-i-hate-you-you-cause-me-too-much-friction.aspx