I am learning to use unit test, i create a project, add xunit reference.
And following codes:
namespace UnitTestProject
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[Fact]
private void test(int number1, string number2)
{
int result = number1 + Convert.ToInt32(number2);
Assert.IsType(Type.GetType("Int32"), result);
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
When i run the test using xunit gui tool, it said:
UnitTestProject.Form1.test : System.InvalidOperationException : Fact
method UnitTestProject.Form1.test cannot have parameters Stack Trace:
於 Xunit.Sdk.FactCommand.Execute(Object testClass)
Xunit.Sdk.FixtureCommand.Execute(Object testClass)
Xunit.Sdk.BeforeAfterCommand.Execute(Object testClass)
Xunit.Sdk.LifetimeCommand.Execute(Object testClass)
Xunit.Sdk.ExceptionAndOutputCaptureCommand.Execute(Object testClass)
So, how can i test the method/function with parameters?
Also you can use [Theory] instead of [Fact]. It will allow you to create test methods with different parameters.
E.g.
[Theory]
[InlineData(1, "22")]
[InlineData(-1, "23")]
[InlineData(0, "-25")]
public void test(int number1, string number2)
{
int result = number1 + Convert.ToInt32(number2);
Assert.IsType(Type.GetType("Int32"), result);
}
p.s. With xUnit it would be better to make test methods public.
About random values and inline methods/variables in tests.
This code generates 100 random int/string pairs for your test.
[Theory]
[PropertyData("GetTestData")]
public void test(int number1, string number2)
{
int result = number1 + Convert.ToInt32(number2);
var expectedType = Type.GetType("System.Int32");
Assert.IsType(expectedType, result);
}
public static IEnumerable<object[]> GetTestData
{
get { return Enumerable.Repeat(0, 100).Select(x => GenerateTestData()); }
}
private static object[] GenerateTestData()
{
var rand = new Random(0);
return new object[] {rand.Next(0,100), rand.Next(0,100).ToString()};
}
How would xunit know what to supply as values for the arguments? A unit test needs to be a self contained test which sets up an environment with data, performs the required action, and then asserts that the results are what are expected. Your test is not self contained because it relies on external values for number1 and number2. Try the following:
[Fact]
private void TestAdd() {
//arrange
int number1 = 10;
string number2 = "10";
//act
object result = Add(number1,number2);
//assert
Assert.IsType(Type.GetType("Int32"), result);
}
private object Add(int number1, string number2)
{
return number1 + Convert.ToInt32(number2);
}
Something to note, what you are trying to do (parameterized unit testing) is possible with the Pex tool
Related
I am very confused about something in java. So the project I was given is write stacks in java, and the program begins with public class Stack<T extends Comparable<? super T>>. However, when trying to run it in my testing program, no matter the kind of Object I throw at it (Integer, String), it all return the error Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable. My question is how does this sort of generics that implement generic T but also extends Comparable work, and why String still returned the error message (I thought String already implemented Comparable<String>?). Thanks in advance for taking the time to read the question! Here is the rough outline of the code:
public class Stack <T extends Comparable<? super T>>{
private T[] arr;
private int ptr;
private int size;
public Stack(){
this.size = 20;
arr = (T[]) new Object[size];
ptr = -1;
}
public boolean push(T element){
try {
arr[ptr+1] = element;
ptr++;
return true;
}
catch (Exception e) {
return false;
}
}
public T[] toArray(){
return arr;
}
}
I got this error from creating a JUnit testing class, with the implementation of something like:
import static org.junit.Assert.assertEquals;
public class StackTester{
#Test
public void testPush(){
Stack<String> st = new Stack<String>();
for (int i = 0; i < 5; i++){
String var = new Integer(i).toString();
st.push(var);
}
assertEquals(new Integer[]{"3","4","5"}, st.toArray());
}
}
public class StackTester{
#Test
public void testPush(){
Stack<String> st = new Stack<String>();
//normal case
for (int i = 0; i < 5; i++){
String var = new Integer(i).toString();
st.push(var);
}
assertEquals(new Integer[]{3,4,5}, st.toArray());
}
}
Also, I have not added a compareTo method as I don't know what it should compare to, and I don't think there's a particular use case for adding that method. I should add that the goal of this project is to use stacks to manipulate Strings (such as going from infix to postfix).
P.S: I would also mention that I don't really need to compare stacks in my project, which is why the stack class itself is not implementing the Comparable interface.
I'm trying to find a nice way to add a prefix to my logs without passing it on every calls, without instanciate Logger again.
The purpose is to trace Rest calls individually.
(The prefix would be re-generated on each call using UUID)
This would be like
#RestController
class MyClass {
//Here the prefix is initialise once
//default value is X
Logger LOG = LoggerFactory.getLogger(MyClass.class);
#RequestMapping("/a")
void methodA() {
LOG.debug("foo");
}
#RequestMapping("/b")
void methodB() {
LOG.setPrefix("B");
LOG.debug("bar");
}
with this output
[...] [prefix X] foo
[...] [prefix B] bar
As you've said you're using Logback, here's a couple options to do the kind of thing you're trying to do:
Markers
Each log entry can have a "marker" established for it. (The best documentation I've seen for it is in the SLF4J FAQ.) Something like:
class MyClass {
Marker methodBMarker = MarkerFactory.getMarker("B");
Logger logger = LoggerFactory.getLogger(MyClass.class);
…
void methodB() {
logger.debug(methodBMarker, "bar");
}
}
You would need to update all log entries in each method to use the appropriate marker. You can then put %marker in your layout to put the log entry's marker into the log.
MDC
The other option is to use the "Mapped Diagnostic Context" functionality to specify the current "context" for each log entry.
class MyClass {
Logger logger = LoggerFactory.getLogger(MyClass.class);
…
void methodB() {
MDC.put("method", "b");
try {
…
logger.debug("bar");
…
} finally {
MDC.clear();
}
}
}
You would then use %mdc{method} in your layout to output that particular MDC value. Note that MDC is really intended to be used for per-thread values like something web-connection-specific, so it's important to ensure that it's cleared out of what you don't want when you're leaving the context you want the value logged in.
Please see http://www.slf4j.org/extensions.html#event_logger for an example of how to use the MDC. You do not have to use the EventLogger. Once you set things in the MDC they are present in every log record.
A Marker does not meet your criteria since it has to be specified on every call.
Here's my MDC implementation explained to share my experiments with MDC.
//In this abstract class i'm defining initLogData methods to set MDC context
//It would be inherited by Controller and other classes who needs logging with traced transactions
public abstract class AbstractService {
protected LogData initLogData() {
return LogData.init();
}
protected LogData initLogData(String tName) {
return LogData.init(tName);
}
}
//LogData holds the MDC logic
public class LogData {
private final static int nRandom = 8;
//this keys are defined in logback pattern (see below)
private final static String tIdKey = "TID";
private final static String tNameKey = "TNAME";
//Transaction id
private String tId;
//Transaction name
private String tName;
public String getTId() {
return tId;
}
public void setTId(String tId) {
this.tId = tId;
}
public String gettName() {
return tName;
}
public void settName(String tName) {
this.tName = tName;
}
//random transaction id
//I'm not using uuid since its too longs and perfect unicity is not critical here
public String createTId(){
Random r = new Random();
StringBuilder sb = new StringBuilder();
while(sb.length() < nRandom){
sb.append(Integer.toHexString(r.nextInt()));
}
return sb.toString().substring(0, nRandom);
}
//private constructors (use init() methods to set LogData)
private LogData(String tId, String tName) {
this.tId = tId;
this.tName = tName;
}
private LogData(String tName) {
this.tId = createTId();
this.tName = tName;
}
private LogData() {
this.tId = createTId();
}
//init MDC with cascading calls processing (using same id/name within same context
//even if init() is called again)
public static LogData init(String tName) {
String previousTId = MDC.get(tIdKey);
String previousTName = MDC.get(tNameKey);
MDC.clear();
LogData logData = null;
if(previousTId != null) {
logData = new LogData(previousTId, previousTName);
} else {
logData = new LogData(tName);
}
MDC.put(tIdKey, logData.getTId());
MDC.put(tNameKey, logData.gettName());
return logData;
}
//init MDC without cascading calls management (new keys are generated for each init() call)
public static LogData init() {
MDC.clear();
LogData logData = new LogData();
MDC.put(tIdKey, logData.getTId());
return logData;
}
}
//logback.xml : values to include in log pattern
[%X{TID}] [%X{TNAME}]
#RestController
#RequestMapping("/test")
public class RestControllerTest extends AbstractRestService {
private final Logger LOG = LoggerFactory.getLogger(ServiceRestEntrypointStatus.class);
#RequestMapping(value="/testA")
public void testA() {
initLogData("testA");
LOG.debug("This is A");
}
#RequestMapping(value="/testB")
public void testB() {
initLogData("testA");
LOG.debug("This is B");
}
#RequestMapping(value="/testC")
public void testC() {
initLogData("testC");
LOG.debug("This is C");
testA();
testB();
}
}
Calling RestControllerTest mapped /test/testA produces :
[fdb5d310] [testA] This is A
Calling /test/testC produces (id and name are kept even if initLogData is called in sub methods):
[c7b0af53] [testC] This is C
[c7b0af53] [testC] This is A
[c7b0af53] [testC] This is B
I'm trying to start a UI application from a java based Windows Service. If figured out so far, that the only approach to make this work is to get a list of sessions, find the one thats currently active, get the user handle for that session and finally create a new process for the given user.
I'm starting off by implementing the session enumeration using WTSEnumerateSessions, yet I'm struggling to get this working. The problem seems to be my mapping of the "_Out_ PWTS_SESSION_INFO *ppSessionInfo" parameter. I wrote the following code:
public interface Wtsapi32 extends StdCallLibrary {
Wtsapi32 INSTANCE = (Wtsapi32) Native.loadLibrary("Wtsapi32", Wtsapi32.class, W32APIOptions.DEFAULT_OPTIONS);
boolean WTSEnumerateSessions(IntByReference hServer, int Reserved, int Version, WTS_SESSION_INFO.ByReference[] ppSessionInfo, IntByReference pCount) throws LastErrorException;
class WTS_SESSION_INFO extends Structure {
public static class ByReference extends WTS_SESSION_INFO implements Structure.ByReference {}
public int sessionId;
public String pWinStationName;
public int state;
#Override
protected List getFieldOrder() {
return Arrays.asList("sessionId", "pWinStationName", "state");
}
}
}
On trying invoking the code with something like this:
public static void main(String[] argv) {
Wtsapi32.WTS_SESSION_INFO.ByReference[] sessionInfo = null;
IntByReference sessionCount = new IntByReference();
try {
if (Wtsapi32.INSTANCE.WTSEnumerateSessions(new IntByReference(0), 0, 1, sessionInfo, sessionCount)) {
System.out.println("success :-)");
}
} catch (LastErrorException ex) {
ex.printStackTrace();
}
}
I get a error code 1784 - ERROR_INVALID_USER_BUFFER. What would be the correct mapping for said API call from JNA?
Update:
I have tried a version suggested Remy Lebeau, but this gives me an Invalid memory access exception:
public interface Wtsapi32 extends StdCallLibrary {
Wtsapi32 INSTANCE = (Wtsapi32) Native.loadLibrary("Wtsapi32", Wtsapi32.class, W32APIOptions.DEFAULT_OPTIONS);
boolean WTSEnumerateSessions(IntByReference hServer, int Reserved, int Version, PointerByReference ppSessionInfo, IntByReference pCount) throws LastErrorException;
class WTS_SESSION_INFO extends Structure {
public static class ByReference extends WTS_SESSION_INFO implements Structure.ByReference {}
public int sessionId;
public String pWinStationName;
public int state;
#Override
protected List getFieldOrder() {
return Arrays.asList("sessionId", "pWinStationName", "state");
}
public WTS_SESSION_INFO() {}
public WTS_SESSION_INFO(Pointer p) {
super(p);
}
}
}
Main:
PointerByReference sessionInfoPtr = new PointerByReference();
IntByReference sessionCount = new IntByReference();
try {
if (Wtsapi32.INSTANCE.WTSEnumerateSessions(new IntByReference(0), 0, 1, sessionInfoPtr, sessionCount)) {
System.out.println("success :-)");
}
} catch (LastErrorException ex) {
ex.printStackTrace();
}
WTSEnumerateSessions() returns:
a pointer to an array of WTS_SESSION_INFO structures
a pointer to a DWORD of the number of elements in the the array.
So you need to pass a PointerByReference for the ppSessionInfo parameter, and a IntByReference for the pCount parameters. You can then use the values being pointed at by those pointers to access the array elements as needed. There is an example of this documented here:
JNA Example #7: Retrieve an Array of Structs from C
Also, your code is using an IntByReference for the hServer parameter. It needs to be a com.sun.jna.platform.win32.WinNT.HANDLE instead, or at least a Pointer. In C, a Win32 HANDLE is just a void* pointer. You need to set the first parameter to Pointer.NULL (which is what WTS_CURRENT_SERVER_HANDLE is defined as in C) to enumerate the sessions of the local server. IntByReference(0) is not the same thing as Pointer.NULL.
And don't forget to call WTSFreeMemory() to free the array data when you are done using it.
Try something like this:
public interface Wtsapi32 extends StdCallLibrary {
Wtsapi32 INSTANCE = (Wtsapi32) Native.loadLibrary("Wtsapi32", Wtsapi32.class, W32APIOptions.DEFAULT_OPTIONS);
boolean WTSEnumerateSessions(Pointer hServer, int Reserved, int Version, PointerByReference ppSessionInfo, IntByReference pCount) throws LastErrorException;
void WTSFreeMemory(Pointer pMemory);
class WTS_SESSION_INFO extends Structure {
public static class ByReference extends WTS_SESSION_INFO implements Structure.ByReference {}
public int sessionId;
public String pWinStationName;
public int state;
public WTS_SESSION_INFO() {}
public WTS_SESSION_INFO(Pointer p) {
super(p);
}
#Override
protected List getFieldOrder() {
return Arrays.asList("sessionId", "pWinStationName", "state");
}
}
}
public static void main(String[] argv) {
PointerByReference sessionInfoPtr = new PointerByReference();
IntByReference sessionCount = new IntByReference();
try {
if (Wtsapi32.INSTANCE.WTSEnumerateSessions(Pointer.NULL, 0, 1, sessionInfoPtr, sessionCount)) {
Pointer sessionInfo = sessionInfoPtr.getValue();
int count = sessionCount.getValue();
Wtsapi32.INSTANCE.WTS_SESSION_INFO arrRef = new Wtsapi32.INSTANCE.WTS_SESSION_INFO(sessionInfo);
arrRef.read(); // <-- not sure why this is here
Wtsapi32.INSTANCE.WTS_SESSION_INFO[] sessions = (Wtsapi32.INSTANCE.WTS_SESSION_INFO[])arrRef.toArray(count);
for (Wtsapi32.INSTANCE.WTS_SESSION_INFO session : sessions) {
// use session as needed...
}
WTSFreeMemory(sessionInfo);
}
} catch (LastErrorException ex) {
ex.printStackTrace();
}
}
I was wondering if C# delegates take up a similar amount of space that C pointers (4 bytes) do when passing to a method.
Edit
delegates only point to methods right? they can't point to structs or classes am i correct.
Yes, delegate only point to methods, one or more.
The parameters must be similar to method.
public class Program
{
public delegate void Del(string message);
public delegate void Multiple();
public static void Main()
{
Del handler = DelegateMethod;
handler("Hello World");
MethodWithCallback(5, 11, handler);
Multiple multiplesMethods = MethodWithException;
multiplesMethods += MethodOk;
Console.WriteLine("Methods: " + multiplesMethods.GetInvocationList().GetLength(0));
multiplesMethods();
}
public static void DelegateMethod(string message)
{
Console.WriteLine(message);
}
public static void MethodWithCallback(int param1, int param2, Del callback)
{
Console.WriteLine("The number is: " + (param1 + param2).ToString());
}
public static void MethodWithException()
{
throw new Exception("Error");
}
public static void MethodOk()
{
Console.WriteLine("Method OK!");
}
}
In the code below, I don't know why the values of variables uNomba and list are NULL when accessed from jButton1ActionPerformed method. I would appreciate your help, on how I can successfully execute "new NewPlayer(uNomba, count, check, list).load();" such that all the values are passed to NewPlayer class. Thank you.
The first class - i.e The NewPlayer class
package mysound;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class NewPlayer extends JPanel implements KeyListener, Runnable{
boolean isUpPressed, isDownPressed, isSpacePressed, isDone;
static JFrame f;
int spacebars=0;
boolean within;
public List spacebarLogMs = new ArrayList();
public List numSbar = new ArrayList();
Calendar cal = Calendar.getInstance();
LogResult logNow = new LogResult();
String directory;
String tabname; //table name used in the database connection
String bdir;
private int uNomba; //user number obtained from NewSound class
private String target;
private int incr;
private int userno;
private boolean moveon=true;
private List randlist;
private List numlist;
public void load() {
f = new JFrame();
f.setSize(600,300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(this);
f.setVisible(true);
setFocusable(true);
addKeyListener(this);
new Thread(this).start();
}
public NewPlayer() {
}
public NewPlayer(int UNOMBA, List NUMLIST){
this.uNomba = UNOMBA; //user number obtained from NewSound class
this.numlist=NUMLIST;
}
public NewPlayer(int USERNO, int INCR, boolean MOVEON, List NUMLIST){
this.userno=USERNO;
this.incr=INCR;
this.moveon=MOVEON;
this.numlist=NUMLIST;
}
public void keyTyped(KeyEvent ke) {
}
public void keyPressed(KeyEvent ke) {
switch(ke.getKeyCode()) {
case KeyEvent.VK_UP: isUpPressed = true; break;
case KeyEvent.VK_DOWN: isDownPressed = true; break;
case KeyEvent.VK_SPACE: isSpacePressed = true;
numSbar.add(System.currentTimeMillis());
System.out.println("That was a spacebar. "+spacebars++);
System.out.println("Current time: "+numSbar);
break;
}
}
public void keyReleased(KeyEvent ke) {
switch(ke.getKeyCode()) {
case KeyEvent.VK_UP: isUpPressed = false; break;
case KeyEvent.VK_DOWN: isDownPressed = false; break;
case KeyEvent.VK_SPACE: isSpacePressed = false; break;
}
}
public void closePrj(){
f.dispose();
}
public void run() { //introduce a target sound
String targetChoice;
int tIndex;
int i;
bdir="C:\\Users\\Abiodun\\Desktop\\testdata\\main\\zero\\atext\\"; //dir for text files
MainPlayer items = new MainPlayer (uNomba);
i=incr;
while(moveon){
System.out.println("Counter i: "+i+" Numlist: "+numlist);
if (i<numlist.size()){
int num = (int) numlist.get(i);
System.out.println("Num :"+num);
items.selectTarget(num);
items.selectChallenge(num);
items.playChallenge();
new WriteTime(bdir).tagTime(numSbar);
items.dataLogger();
moveon=false;
new Continue (uNomba, i, moveon, numlist).load();
}
}
}
}
The second class i.e the Continue class
public class Continue extends javax.swing.JDialog {
private int count;
private int usernumb;
private boolean check;
private int uNomba;
private String cdirectory;
private String cbdir;
private String ctabname;
private String ctarget;
private List list;
/**
* Creates new form Continue
*/
public Continue(java.awt.Frame parent, boolean modal) {
super(parent, modal);
initComponents();
}
public Continue(int CUNOMBA, int COUNT, boolean CHECK, List NLIST){
this.uNomba = CUNOMBA; //user number obtained from NewSound class
this.count=COUNT;
this.check=CHECK;
this.list=NLIST;
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
new NewPlayer().setVisible(false);//closePrj();
count++;
check=true;
new NewPlayer(uNomba, count, check, list).load();
System.out.println("Continue: UserNumber: "+uNumb+", Count: "+count+", Check: "+check+", nList"+lst);
this.setVisible(false);
}
Thanks sgroh. Here is what I just added: I created the following in
In NewPlayer class:
Continue ct = new Continue (new NewPlayer(uNomba, i, moveon, numlist));
In Continue Class,
private NewPlayer np;
public Continue (NewPlayer npy){
this.npy=np;
}
Just a recap, the main problem I am having is that I cannot access the values I passed from NewPlayer class from Continue class. I tested the values in side the following constructor in Continue class but not anywhere else in Continue class.
public Continue(int CUNOMBA, int COUNT, boolean CHECK, List NLIST){
this.uNomba = CUNOMBA; //user number obtained from NewSound class
this.count=COUNT;
this.check=CHECK;
this.nlist=NLIST;
System.out.println("Continue-constructor - uNomba: "+uNomba+", nList: "+list); //works fine! but not outside this constructor.
}
This code even compile, You haven't a constructor default (without fields).
this:
public Continue(java.awt.Frame parent, boolean modal) {
and This:
public Continue(int CUNOMBA, int COUNT, boolean CHECK, List NLIST){
this woun't compile:
Continue ctn = new Continue();
You have to create the Continue object using the right constructor or create the Default constructor.
You want also to print the variable uNumb in the System.out.println that doesn't exists.