I am writing my first ApprovalTest. I need to understand why I am getting the following error when bothg my files are the same.
move /Y "C:\SampleMvc-master\SampleMvc-master\SampleMvc.Tests\Controllers\GoldenMasterTest.About.received.html" "C:\SampleMvc-master\SampleMvc-master\SampleMvc.Tests\Controllers\GoldenMasterTest.About.approved.html"
move /Y "C:\SampleMvc-master\SampleMvc-master\SampleMvc.Tests\Controllers\GoldenMasterTest.About.received.html" "C:\SampleMvc-master\SampleMvc-master\SampleMvc.Tests\Controllers\GoldenMasterTest.About.approved.html"
Test method SampleMvc.Tests.Controllers.GoldenMasterTest.About threw exception:
ApprovalTests.Core.Exceptions.ApprovalMismatchException: Failed Approval: Received file C:\SampleMvc-master\SampleMvc-master\SampleMvc.Tests\Controllers\GoldenMasterTest.About.received.html does not match approved file C:\SampleMvc-master\SampleMvc-master\SampleMvc.Tests\Controllers\GoldenMasterTest.About.approved.html.
My Code is
[TestMethod]
public void About()
{
//AspApprovals.VerifyUrl("http://localhost:50011/Home/About");
MvcApprovals.VerifyMvcPage(new HomeController().About);
}
ApprovalTests uses a "golden master" style of verification. Meaning that you will always fail the 1st time you run. Once it fails, but produces the right result, you will move the file over and then it will pass and continue to pass until something changes.
There are multiple ways to create the golden master, but one easy way in via the command line, which is why you are seeing the
move /Y "C:\SampleMvc-master\SampleMvc-master\SampleMvc.Tests\Controllers\GoldenMasterTest.About.received.html" "C:\SampleMvc-master\SampleMvc-master\SampleMvc.Tests\Controllers\GoldenMasterTest.About.approved.html"
this creates the .approved files from the .received file.
You might also want to check out this video on reporters which will help explore other ways to create the golden master and view the generated results:
Reporter video
or this video, about verifying MVC pages
MVC Approvals Video
Happy Testing!
Related
I added some custom error messages to the APIM according to documentation https://apim.docs.wso2.com/en/4.0.0/troubleshooting/error-handling/ - I created custom file in
<API-M_HOME>/repository/deployment/server/synapse-configs/default/sequences and added references to that file in some of the default files in that directory (so that it is called to transform error message).
Everything seemed to be working just fine until the restart of WSO2 - after that, changes made to default files were present, but the custom file was removed, so that custom error message handling didn't work.
I resolved this by adding non-removable attribute (chattr +i) to the file, but I wonder is there other, more elegant way to prevent the file from being deleted every time restart is being made?
There are 'template' files placed in: <API-M_HOME>/repository/resources/apim-synapse-config. Maybe, those files are overriding files in the ../synapse-configs/default/ location.
Second thing, which came on my mind, is using specific High Avability scenario. Where artifacts are shared files in system as the content synchronization mechanism, it can override local changes.
At the startup gateway removes these files. You can add the following configuration to the deployment.toml and place the file in the sequence directory.
Sample Config:
[apim.sync_runtime_artifacts.gateway.skip_list]
apis = ["api1.xml","api2.xml"]
endpoints = ["endpoint1.xml"]
sequences = ["post_with_nobody.xml"]
local-entries = ["file.xml"]
For your case:
[apim.sync_runtime_artifacts.gateway.skip_list]
sequences = ["name_of_the_file.xml"]
Refer - https://apim.docs.wso2.com/en/latest/install-and-setup/setup/distributed-deployment/deploying-wso2-api-m-in-a-distributed-setup/#configure-the-gateway-nodes
I need a qtf script that selects a line and proceeds. Recording the steps gave the following code:
Window("[windowname]").WinList("ListBox").Select "[Name of the item] "
But when I try to run it I see an error box: Cannot identify the specific item of the ListBox object.
This does not work with any of the lines. I cannot even select one with the arrow down key, the error is always the same.
Please try to highlight WinList from object repository before you run the script. If the object cannot be found, using an updating function to update the object property.
Also, make sure that every time you are running your script for standard window, your screen doesn't minimize.
I have a unit test that creates an error condition. Normally, the class under test writes this error to the logs (using log4j in this case, but I don't think that matters). I can change the log level temporarily, using
Logger targetLogger = Logger.getLogger(ClassUnderTest.class);
Level oldLvl = targetLogger.getLevel();
targetLogger.setLevel(Level.FATAL);
theTestObject.doABadThing();
assertTrue(theTestObject.hadAnError());
targetLogger.setLevel(oldLvl);
but that also means that if an unrelated / unintended error occurs during testing, I won't see that information in the logs either.
Is there a best practice or common pattern I'm supposed to use here? I don't like prodding the log levels if I can help it, but I also don't like having a bunch of ERROR noise in the test output, which could scare future developers.
If your logging layer permits, it is a good practice to make an assertion on the error message. You can do it by implementing your own logger that just asserts on the message (without output), or by using a memory-buffer logger and then check on the contents of the log buffer.
Under no circumstances should the error message end up in the unit-test execution log. This will cause people to get used to errors in the log and mask other errors. In short, your options are:
Most preferred: Catch the message in the harness and assert on it.
Somewhat OK: Raise the level and ignore the message.
Not OK: Don't do anything and let the log message reach stderr/syslog.
The way I approach this assuming an XUnit style of unit testing (Junit,Pyunit, etc)
#Test(expected = MyException)
foo_1() throws Exception
{
theTestObject.doABadThing(); //MyException here
}
The issue with doing logging is that someone needs to go and actually parse the log file, this is time consuming and error prone. However the test will pass above if MyException is generated and fail if it isn't. This in turn allows you to fail the build automatically instead of hoping the tester read the logs correctly.
G'day
Is there a way to force the mail spooler to run, rather than wait for the delay period set in CFAdmin?
I had a look through the admin API and could not see anything, so I suspect the answer might be "no", but I thought perhaps someone knows how to call the underlying process?
The reason for wanting to do this is a bit of an edge case. On our testing server we've got the spooler set to run every 15sec, which - for most things - is fine. However we have an increasing number of unit tests (which run on this same test server) which inspect the content of email messages that have been sent for various elements we need to verify the integrity of. Currently the tests check the Undelivr dir and if the relevant mail message is not found, waits 2sec and tries again, waiting for a total of 20sec before deciding the test needs to be aborted (20sec is an arbitrary amount; 15sec between spool intervals, and some "wriggle room"). This works fine, but it means the unit test suite ends up running slower than it really needs to be, because these email-checking tests have this "up to 20sec" pause in them.
It's not the end of the world, but it's something I'd like to deal with if poss.
I guess one approach I could take is to check the spool dir instead, but I'd rather wait until the email message is "parked" in the Undelivr dir if poss. I'm slightly hesitant to mess with stuff in the spool dir (for no informed reason, granted).
Anyway, all my waffle aside, the short version of the question is "is there any way to force mail spool to run via code?".
Cheers.
<cfobject action="CREATE"
type="JAVA"
class="coldfusion.server.ServiceFactory"
name="factory">
<cfset MailSpoolService = factory.getMailSpoolService()>
<cfset MailSpoolService.restart()>
OK, I've got the official line from one of the Adobe engineers on this: basically what I'm trying to do can't be done, as it currently stands.
There's a method to re-run the email spool, but it's private to the mail spool service.
Oh well.
Cheers to everyone who looked into this for me & offered suggestions.
There's a method to re-run the email spool, but it's private to the
mail spool service.
As I mentioned in the comments, you can invoke a private method by setting its accessibility to true. Not something you want to do "willy-nilly", but probably okay for a unit test.
Disclaimer: I would not swear these are the right methods. But it did seem to kick-off mail processing in my brief tests.
<cfscript>
// Tested with CF 9.0.1
factory = createObject("java", "coldfusion.server.ServiceFactory");
spoolService = factory.getMailSpoolService();
spoolClass = spoolService.getClass();
methodToCall = spoolClass.getDeclaredMethod("refreshSpoolFiles", []);
methodToCall.setAccessible(true);
methodToCall.invoke(spoolService, []);
methodToCall = spoolClass.getDeclaredMethod("deliverStandard", []);
methodToCall.setAccessible(true);
methodToCall.invoke(spoolService, []);
</cfscript>
I've been out of touch with TDD for some time, and am very rusty. I'd appreciate some suggestions on how to TDD the method described below.
The method must find a web.config file in a user supplied application directory. It must then extract and return a connection string from that config file.
It returns null if for any reason the connection string isn't found, be it a bad path, no web.config, or no connection string in web.config.
My initial thoughts are to write a test with setup that creates a directory and writes a web.config file with a connection string. The test would then call my method with the created path and expect a non-null value back, and my initial test run would fail because my method stub always returns null.
Then, implement the method, and run the test expecting a pass. Then, as a pre-test (I forget the term), delete the created directory, and call the method expecting a null value.
First, I wouldn't have the method both find the file and extract the connection string. If your framework doesn't already have a method to determine if a file exists in a given directory, write a method to do then, once you have a file, write a method to extract the connection string from an open stream. For testing, then, you could supply a memory stream instead of having to actually create a directory and file.
Second, if you aren't depending on a failed compile being your first failing test, then write your first attempt at the method to throw a NotImplementedException. It's a small step, but when you write your first test, at least it will fail. Of course, the first test on an empty stream will expect it to return null and the first code you write will be return null, but that's ok. Your next test will force you to change it. Continue on from there until you've got your completed methods.
You appear to have several TestCases with several distinct setUp fixtures.
The FoundDirectory TestCase. The setUp creates the expected, valid file.
This can have several subclasses.
A connection string not found TestCase. The setUp creates the expected, but invalid file.
A bad path TestCase. The setUp creates the expected, but invalid file.
A no web.config TestCase. The setUp creates the expected, but invalid file.
A no connection string in web.config TestCase. The setUp creates the expected, but invalid file.
The DidntFindDirectory TestCase. The setUp assures that the directory doesn't exist.
The DidntFindFile TestCase. The setUp creates the directory but no file.
Make the object that hold you method (or the method itself) dependent on a IConfigLoader of some sort, that you would be able to mock :
public interface IConfigLoader
{
XmlReader LoadAppConfigFrom(string path);
}
Use it from your method to get the XML file you want to parse.
I suggest that the story in your question mixes several issues:
finding and opening a file,
loading data into a "configuration" (however represented)
attempting to get a specific parameter from a "configuration"
Point 3 is now a matter of how a Configuration behaves, and can be developed in TDD fashion.
Point 2 is now a matter of how a Configuration is constructed (e.g by a ConfigurationLoader), and can be developed in TDD fashion (e.g. against a StringReader).
Point 1 is now a matter of whether you can open a Reader for a specified file path. It is easy to add after completing point 2.