In my controller's action to upload file I have a validation rule['file' => 'image'];
I create a test UploadedFile instace like this:
$uploadedFile = new UploadedFile(base_path(self::UPLOAD_PATH), $name, $mimeType, null, null, true);
As you can see, the 6th parameter ($test) is true, it's required for testing. But, during tests, when the $uploadedFile come to Validator, parameter $test is false and the rest of the instance is the same as was created.
Is there's another way to test file uploading? Or how can I fix this?
You should now use:
\Illuminate\Http\UploadedFile
instead of
\Symfony\Component\HttpFoundation\File\UploadedFile
to create UploadedFile object. If you want take a look at detailed explanation for this.
Related
I am asking you for help. I have created a DTO that looks like it (this is a smaller version) :
export class OfImportDto {
#IsString({
message: "should be a valid product code"
})
productCode: string;
#IsString({
message: "Enter the proper product description"
})
productDescription: string;
#IsDateString({
message: "should be a valid date format, for example : 2017-06-07T14:34:08+04:00"
})
manufacturingDate : Date
#IsInt({
message: "should be a valid planned quantity number"
})
#IsPositive()
plannedQuantity: number;
the thing is that i am asking to test that, with a unit test and not a E2E test. And I Don't know how to do that. For instance, I would like to unit test
1/ if my product code is well a string, a string should be created, if not, throw my exception
2/ if my product description is well a string, a string should be created, if not, throw my exception
...
and so on.
So, can I made a spec.ts file to test that? If yes, how?
If not, is it better to test it within the service.spec.ts? If so, how?
Thank you very much, any help would be very helpful :)
You should create a separate DTO specific file like of-import.dto.spec.ts for unit tests of your DTOs. Let's see how to test a DTO in Nest.js step by step.
TLDR: Your DTO's unit test
To understand it line by line, continue reading:
it('should throw when the planned quantity is a negative number.', async () => {
const importInfo = { productCode: 4567, plannedQuanity: -10 }
const ofImportDto = plainToInstance(OfImportDto, importInfo)
const errors = await validate(ofImportDto)
expect(errors.length).not.toBe(0)
expect(stringified(errors)).toContain(`Planned Quantity must be a positive number.`)
}
Create a plain object to test
The following is an object that you would like to test for validation:
const importInfo = { productCode: 4567, plannedQuanity: -10 }
If your test object has nested objects or it's too big, you can skip those complex properties. We'll see how to deal with that.
Convert the test object to the type of DTO
Use plainToinstace() function from the class-transformer package:
const ofImportDto = plainToInstance(OfImportDto, importInfo)
This will turn your plain test object to the object of the type of your DTO, that is, OfImportDto.
If you have any transformations in your DTO, like trimming spaces of the values of properties, they are applied at this point. If you just intend to test the transformations, you can assert now, you don't have to call the following validate() function for testing transformations.
Emulate the validation
Use the validate() function from the class-validator package:
const errors = await validate(ofImportDto)
If you skipped some properties while creating the test object, you can deal with that like the following:
const errors = await validate(ofImportDto, { skipMissingProperties: true })
Now the validation will ignore the missing properties.
Assert the errors
Assert that the errors array is not empty and it contains your custom error message:
expect(errors.length).not.toBe(0)
expect(stringified(errors)).toContain(`Planned Quantity must be a positive number.`)
Here stringified() is a helper function to convert the errors object to a JSON string, so we can search if it contains our custom error message:
export function stringified(errors: ValidationError[]): string {
return JSON.stringify(errors)
}
That's it! Hope that helps.
It would be possible to create a OfImportDTO.spec.ts file (or whatever your original file is called), but the thing is, there isn't any logic here to test. The closest thing you could do is create an instance of a Validator from class-validator and then instantiate an instance of the OfImportDto and then check that the class passes validation. If you add logic to it (e.g. getters and setters with specific functions) then it could make sense for unit testing, but otherwise, this is basically an interface being called a class so it exists at runtime for class-validator
I'm new to unit / integration testing and I want to do an integration test of my controller which looks simplified like this:
// ItemsController.php
public function edit() {
// some edited item
$itemEntity
// some keywords
$keywordEntities = [keyword1, keyword2, ...]
// save item entity
if (!$this->Items->save($itemEntity)) {
// do some error handling
}
// add/replace item's keywords
if (!$this->Items->Keywords->replaceLinks($itemEntity, $keywordEntities)) {
// do some error handling
}
}
I have the models Items and Keywords where Items belongsToMany Keywords. I want to test the error handling parts of the controller. So I have to mock the save() and replaceLinks() methods that they will return false.
My integration test looks like this:
// ItemsControllerTest.php
public function testEdit() {
// mock save method
$model = $this->getMockForModel('Items', ['save']);
$model->expects($this->any())->method('save')->will($this->returnValue(false));
// call the edit method of the controller and do some assertions...
}
This is working fine for the save() method. But it is not working for the replaceLinks() method. Obviously because it is not part of the model.
I've also tried something like this:
$method = $this->getMockBuilder(BelongsToMany::class)
->setConstructorArgs([
'Keywords', [
'foreignKey' => 'item_id',
'targetForeignKey' => 'keyword_id',
'joinTable' => 'items_keywords'
]
])
->setMethods(['replaceLinks'])
->getMock();
$method->expects($this->any())->method('replaceLinks')->will($this->returnValue(false));
But this is also not working. Any hints for mocking the replaceLinks() method?
When doing controller tests, I usually try to mock as less as possible, personally if I want to test error handling in controllers, I try to trigger actual errors, for example by providing data that fails application/validation rules. If that is a viable option, then you might want to give it a try.
That being said, mocking the association's method should work the way as shown in your example, but you'd also need to replace the actual association object with your mock, because unlike models, associations do not have a global registry in which the mocks could be placed (that's what getMockForModel() will do for you) so that your application code would use them without further intervention.
Something like this should do it:
$KeywordsAssociationMock = $this
->getMockBuilder(BelongsToMany::class) /* ... */;
$associations = $this
->getTableLocator()
->get('Items')
->associations();
$associations->add('Keywords', $KeywordsAssociationMock);
This would modify the Items table object in the table registry, and replace (the association collection's add() acts more like a setter, ie it overwrites) its actual Keywords association with the mocked one. If you'd use that together with mocking Items, then you must ensure that the Items mock is created in beforehand, as otherwise the table retrieved in the above example would not be the mocked one!
Given this validator:
public ThingValidator()
{
RuleSet("Subgroup", () =>
{
RuleFor(x => x.Apple).NotEmpty();
RuleFor(x => x.Peach).NotEmpty();
});
}
According to the documentation, the 'ruleSet' option should use my named ruleset. However, the suleSet symbol cannot be resolved.
var validator = new ThingValidator();
var thing = new Constituent();
var results = validator.Validate(thing, ruleSet: "Subgroup");
What am I missing?
I was stuck on this as well, but when I looked into the code, I found that while IValidator<T> has a Validate method, there are also Validate extensions methods in DefaultValidatorExtensions. The call with the ruleSet parameter in #mmcglynn's answer is actually to this extension method from DefaultValidatorExtensions:
public static ValidationResult Validate<T>(
this IValidator<T> validator, T instance,
IValidatorSelector selector = null,
string ruleSet = null)
This is why Resharper thinks that the ruleSet variable is unused - because it is not actually passed in. The string "children" passed in is for the 3rd parameter called ruleset, whereas the second parameter (which can take the RulesetValidatorSelector object) defaults to null.
This is extension method, declare namespace using FluentValidation and you can use it.
I think what you need it:
var results = validator.Validate(constituent, new RulesetValidatorSelector("Subgroup"));
or, closer to the example in the FluentValidation documentation
RulesetValidatorSelector ruleSet = new RulesetValidatorSelector();
var results = validator.Validate(constituent, ruleSet: "Children");
This will work, but ReSharper thinks that the ruleSet local variable is unused.
I'm looking for a way to share data between HtmlHelpers. The goal is to set configuration once instead of passing a parameter with each call. In the example below, I'm setting the form type to determine the grid configuration:
#{ Html.SetFormType(HtmlHelpers.FormType.Boxed); }
#Html.FormItemFor(m => m.LoginName)
#Html.FormItemFor(m => m.Password)
public static void SetFormType(this HtmlHelper helper, FormType formType)
{
helper.ViewBag.FormType = formType;
helper.ViewContext.ViewBag.FormType = formType;
}
Setting ViewBag does not persist through subsequent #Html calls. Setting ViewContext.ViewBag persists, but is it safe to do so?
The existing method EnableUnobtrusiveJavaScript is set in an instance of the ScopeCache class, which in turn is added to HttpContext.Items. Perhaps that's also a candidate to store my data?
You can use the request-based-scope object of HttpContext.Current.Items because HttpContext.Current is actually the only container that is unique and always there in a request.
Cheers
PS: don't put everything directly into the items. Just add a controller-item there and work on this.
In my app, I use Groovy as a scripting language. To make things easier for my customers, I have a global scope where I define helper classes and constants.
Currently, I need to run the script (which builds the global scope) every time a user script is executed:
context = setupGroovy();
runScript( context, "global.groovy" ); // Can I avoid doing this step every time?
runScript( context, "user.groovy" );
Is there a way to setup this global scope once and just tell the embedded script interpreter: "Look here if you can't find a variable"? That way, I could run the global script once.
Note: Security is not an issue here but if you know a way to make sure the user can't modify the global scope, that's an additional plus.
Shamelessly stolen from groovy.codehaus :
The most complete solution for people
who want to embed groovy scripts into
their servers and have them reloaded
on modification is the
GroovyScriptEngine. You initialize the
GroovyScriptEngine with a set of
CLASSPATH like roots that can be URLs
or directory names. You can then
execute any Groovy script within those
roots. The GSE will also track
dependencies between scripts so that
if any dependent script is modified
the whole tree will be recompiled and
reloaded.
Additionally, each time you run a
script you can pass in a Binding that
contains properties that the script
can access. Any properties set in the
script will also be available in that
binding after the script has run. Here
is a simple example:
/my/groovy/script/path/hello.groovy:
output = "Hello, ${input}!"
import groovy.lang.Binding;
import groovy.util.GroovyScriptEngine;
String[] roots = new String[] { "/my/groovy/script/path" };
GroovyScriptEngine gse = new GroovyScriptEngine(roots);
Binding binding = new Binding();
binding.setVariable("input", "world");
gse.run("hello.groovy", binding);
System.out.println(binding.getVariable("output"));
This will print "Hello, world!".
Found: here
Would something like that work for you?
A simple solution is to use the code from groovy.lang.GroovyShell: You can precompile the script like so:
GroovyCodeSource gcs = AccessController.doPrivileged( new PrivilegedAction<GroovyCodeSource>() {
public GroovyCodeSource run() {
return new GroovyCodeSource( scriptCode, fileName, GroovyShell.DEFAULT_CODE_BASE );
}
} );
GroovyClassLoader loader = AccessController.doPrivileged( new PrivilegedAction<GroovyClassLoader>() {
public GroovyClassLoader run() {
return new GroovyClassLoader( parentLoader, CompilerConfiguration.DEFAULT );
}
} );
Class<?> scriptClass = loader.parseClass( gcs, false );
That's was the expensive part. Now use InvokeHelper to bind the compiled code to a context (with global variables) and run it:
Binding context = new javax.script.Binding();
Script script = InvokerHelper.createScript(scriptClass, context);
script.run();