#include<queue>
#include<vector>
#include<cstdio>
#include<algorithm>
#define pc putchar
#define gc getchar()
#define rep(a,b,c) for(int a = b;a <= c;++ a)
#define per(a,b,c) for(int a = b;a >= c;-- a)
inline int read() {
int x = 0,f = 1;
char c = gc;
while(c < '0' || c > '9') c = gc;
while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = gc;
return x * f ;
}
void print(int x) {
if(x < 0) {
pc('-'); x = -x;
}
if(x >= 10) print(x / 10);
pc(x % 10 + '0');
}
const int maxn = 100007;
int a[maxn << 1];
struct node {
int v,next;
bool cut;
} edge[maxn << 1];
int head[maxn],num = 1;
inline void add_edge(int u,int v) {
edge[++ num].v = v; edge[num].next = head[u];head[u] = num;
e[num].cut = 0 ;
}
bool vis[maxn];
void tarjan(int x,int fa) {
low[x] = dfn[x] = ++ index;
stk[++ top] = x;
vis[x] = 1;
for(int i = head[x];i;i = edge[i].next) {
int v = edge[i].v;
if(v == fa) continue;
if(!dfn[v]) {
tarjan(v,x);
low[x] = std::min(low[x],low[v]);
if(low[v] > dfn[u]) {
bridge ++;
edge[i].cut = true;
edge[i ^ 1].cut = true;
}
}
else if(vis[v] && low[u] > dfn[v])
low[u] = dfn[v];
}
if(dfn[x] == low[x]) {
}
void solve() {
n = read();m = read();
for(int u,v,i = 1;i <= m;++ i) {
u = read(),v = read();
add_edge(u,v);
add_edge(v,u);
}
memset(dfn,0,sizeof dfn);
top = block = index = bridge = 0;
for(int i = 1;i <= n;++ i) if(!dfn[i]) tarjan(i,i);
}
int main() {
int t = read();
for(int i = 1;i <= t;++ i) {
memset(head,0,szieof head); num = 0;
solve();
}
}