Can an NUnit project load a separate *.config for each assembly that it loads? - automation

If so, how?
If not, what is the best workaround? Particularly, I'm trying to automate running unit tests in the GUI test runner on arbitrary developers' machines.

The best solution is to make the classes you want to unit test accept configuration settings in their constructors rather than read them from configuration files.
Make callers responsible for obtaining configuration data: decouple your classes from specific configuration sources and eliminate hidden dependencies in one fell swoop.

Yes, you can configure NUnit to do this. If you specify domainUsage="Multiple" in your project's settings, it will load .dll.config for each assembly in your NUnit project.
Here's a sample project file with this setting specified:
<NUnitProject>
<Settings activeConfig="Debug" domainUsage="Multiple" />
<Config name="Debug" binpathtype="Auto" >
<assembly path="Assembly1.dll" />
<assembly path="Assembly2.dll" />
</Config>
<Config name="Release" binpathtype="Auto" />
</NUnitProject>
In this case, NUnit will load Assembly1.dll.config and Assembly2.dll.config automatically.

Related

Enable perf4j profiled annotation in intellij

I'm trying to enable perf4j annotations in intellij but I'm struggling to configure correctly AspectJ. More specifically the log file is created correctly but lacks of any data from the annotated method.
These are the relevant extracts of configuration:
logback.xml
<configuration debug="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="statistics" class="ch.qos.logback.core.FileAppender">
<file>./target/statisticsLogback.log</file>
<append>false</append>
<layout>
<pattern>%msg%n</pattern>
</layout>
</appender>
<appender name="coalescingStatistics" class="org.perf4j.logback.AsyncCoalescingStatisticsAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<timeSlice>1000</timeSlice>
<appender-ref ref="statistics"/>
</appender>
<appender name="listAppender" class="ch.qos.logback.core.read.ListAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<timeSlice>1000</timeSlice>
</appender>
<logger name="org.perf4j.TimingLogger" level="info">
<appender-ref ref="coalescingStatistics" />
<appender-ref ref="listAppender"/>
</logger>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
aop.xml
<?xml version="1.0" encoding="UTF-8"?>
<aspectj>
<!--
We only want to weave in the log4j TimingAspect into the #Profiled classes.
Note that Perf4J provides TimingAspects for the most popular Java logging
frameworks and facades: log4j, java.util.logging, Apache Commons Logging
and SLF4J. The TimingAspect you specify here will depend on which logging
framework you wish to use in your code.
-->
<aspects>
<aspect name="org.perf4j.slf4j.aop.TimingAspect"/>
<!-- if SLF4J/logback use org.perf4j.slf4j.aop.TimingAspect instead -->
</aspects>
<weaver options="-verbose -showWeaveInfo">
<!--
Here is where we specify the classes to be woven. You can specify package
names like com.company.project.*
-->
<include within="com.mycode.myproject.mypackage.*"/>
<include within="org.perf4j.slf4j.aop.*"/>
</weaver>
</aspectj>
Finally the related test method is tagged with the #Profiled annotation, this is part of the package defined in the aop.xml.
This configuration results in the log file being produced (which suggests that the logback.xml is configured correctly, however it only contains headers and no statistics from the tagged method.
The main question I have is where the AspectJ configuration should go within Intellij, I have included the aop.xml under a manually created META-INF folder in the src folder but I'm not sure this is detected by AspectJ at all.
Thanks in advance
UPDATE
I have made some progress on this since my initial post, specifically introducing two changes:
i) included -javaagent:lib\aspectjweaver.jar
ii) moved the aop.xml into a META-INF folder.
The aop configuration is now being picked up as it logs the configuration details and it also mentions the method being profiled.
The issue is now that the thread being profiled crashes, it doesn't log any exceptions but via debug the issue seems to be related to a ClassNotFoundException in org.aspectj.runtime.reflect.Factory when trying to instantiate org.aspectj.runtime.reflect.JoinPointImpl.
To isolate the issue i have removed all the maven imports of aspectJ and used the jars provided by the installation package but the issue persists, also the fact that the application crashes without any logging makes the issue tracking harder.
UPDATE
To clarify:
After reading more about this including the manual in the wayback link (thanks for that) I realised I was mixing up load-time / compile-time approach. Since then I tried both methods as described in the guide but with the same results described in my earlier update.
As per above, I do start the application with aspectj weaver option (-javaagent)
The build is done via IDE, as per above at the moment I have removed the aspectj / perf4j dependencies from Maven and linked to local jars
As mentioned the aop.xml does get picked up as mentioned in the update with no errors or warning, just confirmation of the weaved method
Okay, I have added a full Maven example to a GitHub repo which you can just clone and play around with.
Some basic things to consider:
For compile-time weaving (CTW) you need aspectjrt.jar on the classpath when compiling and running the code. You also need to use the AspectJ compiler to build the project, a normal Java compiler is not enough.
For load-time weaving (LTW) you need aspectjweaver.jar as a Java agent on the command line when running the code: -javaagent:/path/to/aspectjweaver.jar. You also need to add it as a VM argument to your LTW run configuration in IDEA.
For LTW you also need META-INF/aop.xml in your resources folder. Please also note that in order to encompass subpackages you should use the ..* notation, not just .*, e.g. <include within="de.scrum_master..*"/>.
You find more information in my project's read-me file.
P.S.: The Perf4J documentation is outdated and the project unmaintained. Thus, it still mentions AspectJ 1.6.x as necessary dependencies. I built and ran everything with the latest AspectJ 1.8.10 and it runs just fine, both from Maven and IDEA.

CruiseControl.NET 1.8.5 - Not creating msbuild-results xml file

I'm pretty new to build servers but have been asked by my employer to do some testing (because F5 is not a build process, as the excellent article by Jeff Atwood says). At this stage, I'm working on getting some sample builds and test reports up and running on a CruiseControl.NET server. So far, I've gotten a build up and running (the configuration file will need some tidying up before adding new builds/projects but the proof of concept is there) but the reporting is causing something of a headache.
The main report I'm looking for is for out NUnit tests and SpecFlow integration tests. The tests run fine (as I'm getting a sensible looking xml file generated) and am looking to merge that in to the main build results so that I can show the results of the NUnit/SpecFlowtests.
Whenever the build completes, the following is reported in the messages (in ViewFarmReport.aspx): "Failing Tasks : XmlLogPublisher "
This combined with the following error reported in the Windows application log (source - CC.Net)
2015-03-24 08:36:52,987 [Initech.SuperCrm-DEV] ERROR CruiseControl.NET [(null)] - Publisher threw exception: ThoughtWorks.CruiseControl.Core.CruiseControlException: Unable to read the contents of the file: C:\CCNet\BuildArtifacts\Initech.SuperCrm-DEV\msbuild-results-7c657954-2c3e-405f-b0f1-7da1299788fd.xml ---> System.IO.FileNotFoundException: Could not find file 'C:\CCNet\BuildArtifacts\Initech.SuperCrm-DEV\msbuild-results-7c657954-2c3e-405f-b0f1-7da1299788fd.xml'.
(company/application name "censored")
This leads me to suspect that the failure to merge in the msbuild results (which I believe CruiseControl.NET automatically scrapes since version... 1.5 or 1.6?) is preventing the NUnit results from being merged in.
There is no msbuild-results file in the BuildArtifacts folder, which does not surprise me as I do not believe my current msbuild configuration allows for xml based logging as I am using the ThoughtWorks.CruiseControl.MsBuild.dll logger.
According to the online documentation for CruiseControl.NET there is XML enabled custom logger: ThoughtWorks.CruiseControl.MsBuild.XmlLogger which can be used, however the download location for this logger: here
appears not to exist any more.
Can anyone say whether I'm thinking along the right lines here and what my options are?
For reference, here is my complete configuration:
<cruisecontrol xmlns:cb="urn:ccnet.config.builder">
<cb:define MSBuildPath="C:\Windows\Microsoft.NET\Framework\v4.0.30319" />
<cb:define WorkingBaseDir="C:\CCNet\Builds" />
<cb:define ArtifactBaseDir="C:\CCNet\BuildArtifacts" />
<cb:define MSBuildLogger="C:\Program Files (x86)\CruiseControl.NET\server
\ThoughtWorks.CruiseControl.MsBuild.dll" />
<cb:define NUnitExe="C:\Jenkins\Nunit\nunit-console.exe" />
<cb:define name="vsts_ci">
<executable>C:\Jenkins\tf.exe</executable>
<server>http://tfs-srv:8080/tfs/LEEDS/</server>
<domain>CONTOSO</domain>
<autoGetSource>true</autoGetSource>
<cleanCopy>true</cleanCopy>
<force>true</force>
<deleteWorkspace>true</deleteWorkspace>
</cb:define>
<project name="Initech.Libraries" description="Shared libraries used in all Initech projects"
queue="Q1">
<state type="state" directory="C:\CCNet\State"/>
<artifactDirectory>$(ArtifactBaseDir)\Initech.Libraries</artifactDirectory>
<workingDirectory>$(WorkingBaseDir)\Initech.Libraries</workingDirectory>
<triggers>
<intervalTrigger
name="continuous"
seconds="30"
buildCondition="IfModificationExists"
initialSeconds="5"/>
</triggers>
<sourcecontrol type="vsts">
<cb:vsts_ci/>
<workspace>CCNET_Initech.Libraries</workspace>
<project>$/InitechLibraries/Initech.Libraries</project>
</sourcecontrol>
</project>
<project name="Initech.SuperCrm-DEV" description="Initech.SuperCrm Application, Development
Version" queue="Q1">
<cb:define ArtifactDirectory="$(ArtifactBaseDir)\Initech.SuperCrm-DEV" />
<cb:define WorkingDirectory="$(WorkingBaseDir)\Initech.SuperCrm-DEV" />
<cb:define OutputDirectory="$(WorkingDirectory)\Initech.SuperCrm\bin\Debug" />
<cb:define ProjectFile="Initech.SuperCrm.sln" />
<cb:define NUnitLog="$(WorkingDirectory)\NunitResults.xml" />
<state type="state" directory="C:\CCNet\State"/>
<artifactDirectory>$(ArtifactDirectory)</artifactDirectory>
<workingDirectory>$(WorkingDirectory)</workingDirectory>
<triggers>
<!-- check the source control every X time for changes,
and run the tasks if changes are found -->
<intervalTrigger
name="continuous"
seconds="30"
buildCondition="IfModificationExists"
initialSeconds="5"/>
</triggers>
<sourcecontrol type="vsts">
<cb:vsts_ci/>
<workspace>CCNET_Initech.SuperCrm-DEV</workspace>
<project>$/InitechSuperCrm/SuperCrm/Initech.SuperCrm-DEV</project>
</sourcecontrol>
<tasks>
<exec>
<executable>C:\Program Files (x86)\DXperience 12.1\Tools\DXperience
\ProjectConverter-console.exe</executable>
<buildArgs>$(WorkingDirectory)</buildArgs>
</exec>
<msbuild>
<executable>$(MSBuildPath)\MSBuild.exe</executable>
<workingDirectory>$(WorkingDirectory)</workingDirectory>
<projectFile>$(ProjectFile)</projectFile>
<timeout>900</timeout>
<logger>$(MSBuildLogger)</logger>
</msbuild>
<exec>
<executable>$(NUnitExe)</executable>
<buildArgs>/xml=$(NUnitLog) /nologo $(WorkingDirectory)\$(ProjectFile)
</buildArgs>
</exec>
</tasks>
<publishers>
<buildpublisher>
<sourceDir>$(OutputDirectory)</sourceDir>
<useLabelSubDirectory>true</useLabelSubDirectory>
<alwaysPublish>false</alwaysPublish>
<cleanPublishDirPriorToCopy>true</cleanPublishDirPriorToCopy>
</buildpublisher>
<merge>
<files>
<file>$(NUnitLog)</file>
</files>
</merge>
<xmllogger logDir="C:\CCNet\BuildArtifacts\Initech.SuperCrm-DEV\buildlogs" />
<artifactcleanup cleanUpMethod="KeepLastXBuilds"
cleanUpValue="50" />
</publishers>
</project>
</cruisecontrol>
I've been tearing my hair while trying to figure this out, and I don't have much to begin with, so any help would be greatly appreciated.
After a prolonged period of banging my head against the wall, I seem to have finally found the solution (well solutions).
1) Kobush.Build.dll (https://www.nuget.org/packages/Kobush.Build/) can be used as the logger for MSBuild. Looking at the attributions in CruiseControl.NET's documentation, it appears to have been written by the same developer (but extended).
2) Some tweaks were needed due to the default location of the msbuild-report output. Because, by default, it was dumped to the buildartifacts folder then it is susceptible to being prematurely deleted.
I no longer clean the publish directory prior to copying (in the buildpublisher) and perform the merge and xmllogger portions of the publisher before artifact cleanup.
As a result, I now have msbuild and nunit output/results integrated in to the main build log and these can be consumed through the CruiseControl.NET dashboard.
There's probably a tidier way of handling this, but at the moment I'm just getting a proof of concept going.

NUnit console can't load assembly for serialization test

Error message:
System.Runtime.Serialization.SerializationException : Unable to find
assembly 'MyCompany.Plates, Version=12.15.0.0, Culture=neutral,
PublicKeyToken=0b9f95a95d107d22'.
+++++++++++++++++++ STACK TRACE: at System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly()
There are two DLL files:
PlatesTests.dll and MyCompany.Plates.dll
The tests are all in PlatesTests.dll. The objects being serialized are in MyCompany.Plates.dll.
When run by passing PlatesTests.dll to nunit-console.exe, everything passes.
However, our build system uses a .nunit file as under:
<NUnitProject>
<Settings activeconfig="Default" />
<Config name="Default" binpathtype="Auto">
<assembly path="..\..\Build Products\ReleaseTests\PlatesTests.dll" />
</Config>
</NUnitProject>
And when the nunit-console is run against this .nunit file, it gives the above error.
How can I fix this problem?
I believe that you have to run the console project with /noshadow
From the documentation
The /noshadow option disables shadow copying of the assembly in order to provide improved performance.
This shadow copying sometimes causes assembly loading to fail for projects.
I fixed this by setting the appbase on the .nunit setting file to point to where PlatesTests.dll and MyCompany.Plates.dll are both located.
The new file looks like this:
<NUnitProject>
<Settings activeconfig="Default" appbase="..\..\Build Products\ReleaseTests" />
<Config name="Default" binpathtype="Auto">
<assembly path="..\..\Build Products\ReleaseTests\PlatesTests.dll" />
</Config>
</NUnitProject>

Better Ways to Maintain Continuous Integration?

I find that I am always tuning and tweaking our CI setup as we add new projects. While there is NO question that the benefits are awesome for existing code that seldom changes, new projects or volitile ones seem to require more work as I have to configure each project to be "intergrated" as well as maintain an ever-growing CCNET.config file. Is there a better strategy short of building an utility to manage adding and modifying a CI setup?
I do a few things to try keep it under control:
1) Split the config file into two. I have one file that mostly stays the same and contains a set of constants e.g.
<?xml version="1.0" encoding="utf-8"?>
<cruisecontrol xmlns:cb="urn:ccnet.config.builder">
<!-- Constant definition used by the projecct config to prevent changes being required for each iteration -->
<cb:define branch="branch name for source control"/>
<cb:define ciserver="Server name in here"/>
<cb:define devenv="Path to DEVENV"/>
<cb:define nunit="Path to NUNIT"/>
<cb:define cruisecontrol="Cruisecontrol Path"/>
<!-- Include file to the standard CI project definitions. This file is kept under source control -->
<cb:include href="config\CCProjects.config"/>
</cruisecontrol>
The use of constants allows you to make a single change and have it propagate through each task in the config file.
See docs
2) Keep the file with the projects in under source control. The project file gets updated as part of the SVN checkout. This helps track changes that get made and let you rollback without too much hassle.
Maybe it has got to the point where CC.Net is working against you rather than for you. I've heard good things about the ease of configuration of other CI servers, like Hudson, but it may not be a good fit with your build environment.
1/ Split your config file as you want
For example, I have a constants section, and each project is an include, so I can update each project quite independently and use constants across projects.
ccnet.config
<cruisecontrol xmlns:cb="urn:ccnet.config.builder">
<!-- Shared constants -->
<cb:define WorkingFolderBase="D:\dev\ContinuousIntegration\WC" />
<cb:define ArtifactFolderBase="D:\dev\ContinuousIntegration\Artifact" />
<cb:define ConfigFolder="projects" />
<cb:define SvnBasePath="http://myserver.com/svn" />
<cb:define SvnUsername="Myusername" />
<cb:define SvnPassword="MyPassword" />
<!-- MyProject1 -->
<cb:include href="projects/MyProject1.config"/>
<!-- MyProject2 -->
<cb:include href="projects/MyProject2.config"/>
</cruisecontrol>
MyProject1.config
<project name="MyProject1" queue="Q1" queuePriority="1">
<artifactDirectory>$(ArtifactFolderBase)\MyProject1</artifactDirectory>
<workingDirectory>$(WorkingFolderBase)\MyProject1</workingDirectory>
<!-- SVN implementation -->
<sourcecontrol type="svn" username="$(SvnUsername)" password="$(SvnPassword)">
<trunkUrl>$(SvnBasePath)/MyProject1/trunk/</trunkUrl>
<workingDirectory>$(WorkingFolderBase)\MyProject1</workingDirectory>
</sourcecontrol>
[...]
</project>
2/ Use version control on CC.NET (I recommand on the whole installation) or on config files.
3/ Keep it simple! have all actions executed by a batch file (Compile applciation, compile tests, run tests, get coverage, static analyser, generate reports ...).

Where is sun-appserv-ant.jar for Glassfish v3

Where is sun-appserv-ant.jar in Glassfish v3
I have created a small sample EJB project and I want to use ant to deploy the application to Glassfish v3.
Ive spent a lot of time on google trying to achieve this and all ant samples seem to refer to a jar file called "sun-appserv-ant.jar" which is supposed to be located in the modules directory of the application server install, however, I cannot find it anywhere, nor can I seem to find the reason why, or if there is even an ant based alternative.
Thanks
The sun-appserv-ant.xml file was not brought forward with v3.
You are not completely stuck though.
You can read about the Ant exec task, which you can use to trigger asadmin commands.
If you are very adventurous, you may want to investigate the bp-project framework that is used by the sample projects that ship with the Java EE 6 SDK.
You can get a peek at the bp-project framework by looking at the code in the glassfish-samples repository.
You should add the glassfish-ant-tasks module through the GlassFish Update Tool
After much agony I found an example of how to use the V3.x ant tools here
The downside, for non-French-speakers, is that it's in French. The upside is that the Java parts are still in Java.
From what I can tell, the Ant tasks now differ significantly from what is documented by Sun (Oracle):
You must use the Glassfish server update tool to get the glassfish-ant-tasks module.
This will cause the file *glassfish_dir*/lib/ant/ant-tasks.jar to be downloaded. That must be included on your classpath
Define an as-ant-init target in your build.xml
<target name="as-ant-init">
<taskdef name="sun-appserv-deploy"
classname="org.glassfish.ant.tasks.DeployTask"
classpath="${build-lib}/ant-tasks.jar" />
<taskdef name="sun-appserv-undeploy"
classname="org.glassfish.ant.tasks.UndeployTask"
classpath="${build-lib}/ant-tasks.jar" />
<taskdef name="sun-appserv-component"
classname="org.glassfish.ant.tasks.ComponentTask"
classpath="${build-lib}/ant-tasks.jar" />
<taskdef name="sun-appserv-admin"
classname="org.glassfish.ant.tasks.AdminTask"
classpath="${build-lib}/ant-tasks.jar" />
<taskdef name="sun-appserv-redeploy"
classname="org.glassfish.ant.tasks.RedeployTask"
classpath="${build-lib}/ant-tasks.jar" />
<taskdef name="sun-appserv-start-server"
classname="org.glassfish.ant.tasks.StartServerTask"
classpath="${build-lib}/ant-tasks.jar" />
<taskdef name="sun-appserv-stop-server"
classname="org.glassfish.ant.tasks.StopServerTask"
classpath="${build-lib}/ant-tasks.jar" />
</target>
Write the deployment target. The rules are similar to what's in the documentation, EXCEPT
A. Remove references to the <server> element that was used in older versions.
B. All of the attributes that would have been attached to <server> in the older version of the API are now attached directly to the containing element, such as <sun-appserv-deploy>, like so:
<target name="deploy">
<sun-appserv-deploy
user="${glassfish.admin-user}"
passwordfile="${glassfish.passwordfile}}"
host="${glassfish.host}"
port="${glassfish.admin-port}"
installDir="${asinstalldir}"
upload="true" >
<component
file="${dist.warfile}"
name="My application"
contextroot="${glassfish.context-root}" />
</sun-appserv-deploy>
</target>